在contenteditable中替换特定单词 [英] Replace specific word in contenteditable

查看:93
本文介绍了在contenteditable中替换特定单词的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个满足的div

I have a contenteditable div

<div id="divTest" contenteditable="true">

我需要从插入位置得到最后一个字,在某些条件下我必须测试并删除它只有特定的字。以下是我的工作方式

I need to get the last word from caret position and on certain condition I have to test and remove this specific word only. Below is how am I doing

$('#divTest').on('keyup focus', function (e) {
           if (e.keyCode == 32) {
               var lastWord = getWordPrecedingCaret(this),                                       spanLastWord = $('#lastWord');

           }
       });

function getWordPrecedingCaret(containerEl) {
               var preceding = "",
                                    sel,
                                    range,
                                    precedingRange;
               if (window.getSelection) {
                   sel = window.getSelection();
                   if (sel.rangeCount > 0) {
                       range = sel.getRangeAt(0).cloneRange();
                       range.collapse(true);
                       range.setStart(containerEl, 0);
                       preceding = range.toString();


                   }
               } else if ((sel = document.selection) && sel.type != "Control") {
                   range = sel.createRange();
                   precedingRange = range.duplicate();
                   precedingRange.moveToElementText(containerEl);
                   precedingRange.setEndPoint("EndToStart", range);
                   preceding = precedingRange.text;
               }

               var words = range.toString().trim().split(' '),
                        lastWord = words[words.length - 1];
                  if (lastWord) {

                   var resultValue = 'some'; // this value is coming from some other function
                   if (resultValue == lastWord) {
                     alert('do nothing');
                       // do nothing
                   }
                 else
                   {
                     alert('replace word');
                     // delete That specific word and replace if with resultValue
                   }
                   return lastWord;

               }
           }

演示: http://codepen.io/anon/pen/ogzpXV

我尝试过range.deleteContents();但这将删除div中的所有内容。
如何只更换特定字?

I have tried range.deleteContents(); but that will delete all the content in the div. How can I replace specific word only?

推荐答案

使用 范围 我们需要保持记住我们正在使用节点,而不仅仅是渲染的文本。您想要操纵的结构是:

To work with Ranges we need to keep in mind that we are working with Nodes, not only the text that is rendered. The structure you want to manipulate is:

<div id="divTest" contenteditable="true"> <-- Element Node
    "some text" <-- TextNode
</div>

但也可能是:

<div id="divTest" contenteditable="true"> <-- Element Node
    "some text" <-- TextNode
    "more text" <-- TextNode
    "" <-- TextNode
</div>

解决您的问题更简单,只能处理一个 TextNode ,我建议使用 normalize() 函数将所有这些函数合并为一个。

To solve your problem is simplier to handle only one TextNode, I propose to use the normalize() function to join all of them into a single one.

然后你只需要设置范围 deleteContents() 。删除后,您可以使用 TextNode 替换/Range.insertNoderel =nofollow noreferrer> insertNode()

Then you only need to set the Range to the word's bounds before deleteContents(). Once deleted, you can insert a new TextNode with the substitution using insertNode().

var wordStart = range.toString().lastIndexOf(lastWord);
var wordEnd = wordStart + lastWord.length;

/* containerEl.firstChild refers to the div's TextNode */                   
range.setStart(containerEl.firstChild, wordStart);
range.setEnd(containerEl.firstChild, wordEnd);
range.deleteContents();
range.insertNode(document.createTextNode(resultValue));

为此,您需要将文本放在单个 TextNode中。但在插入节点之后, div 将包含多个文本节点。要解决此问题,只需致电 normalize() 加入所有 TextNode 元素。

For this to work, you need that the text is in a single TextNode. But after ìnsertNode the div will contain multiple text nodes. To fix this simply call normalize() to join all TextNode elements.

containerEl.normalize();

修改:

正如Basj指出的那样,原始解决方案因多线而失败。这是因为当按下ENTER时,结构会改变:

As Basj points out, the original solution fails for multiline. That's because when hitting ENTER the structure changes from:

<div id="divTest" contenteditable="true"> <-- Element Node
    "some text" <-- TextNode
</div>

类似于:

<div id="divTest" contenteditable="true"> <-- Element Node
    <div>"some text"</div>
    <div>"more text"</div>
</div>

我已经更新了这个答案,但它也值得阅读巴斯的回答在这个问题上:在光标之前替换单词,当多条线在contenteditable时

I've updated this answer, but it's also worth to read Basj's answer at this question: Replace word before cursor, when multiple lines in contenteditable

JSFiddle demo 或runnable code snippet:

JSFiddle demo or runnable code snippet:

document.getElementById('divTest').onkeyup = function (e) {
    if (e.keyCode == 32) {
        getWordPrecedingCaret(this);
    }
};

function getWordPrecedingCaret(containerEl) {
    var preceding = "",
        sel,
        range,
        precedingRange;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount > 0) {
            range = sel.getRangeAt(0).cloneRange();
            range.collapse(true);
            range.setStart(containerEl, 0);
            preceding = range.toString();
        }
    } else if ((sel = document.selection) && sel.type != "Control") {
        range = sel.createRange();
        precedingRange = range.duplicate();
        precedingRange.moveToElementText(containerEl);
        precedingRange.setEndPoint("EndToStart", range);
        preceding = precedingRange.text;
    }

    var words = range.toString().trim().split(' '),
        lastWord = words[words.length - 1];
        
    if (lastWord) {
        var resultValue = 'some'; // this value is coming from some other function
        if (resultValue == lastWord) {
            console.log('do nothing: ' + lastWord);
            // do nothing
        } else {
            console.log('replace word ' + lastWord);
            
            /* Find word start and end */
            var wordStart = range.endContainer.data.lastIndexOf(lastWord);
            var wordEnd = wordStart + lastWord.length;
            console.log("pos: (" + wordStart + ", " + wordEnd + ")");
                           
            range.setStart(range.endContainer, wordStart);
            range.setEnd(range.endContainer, wordEnd);
            range.deleteContents();
            range.insertNode(document.createTextNode(resultValue));
            // delete That specific word and replace if with resultValue

            /* Merge multiple text nodes */            
            containerEl.normalize();
        }
        return lastWord;
    }
}

<div id="divTest" contenteditable="true">Write words here and hit SPACE BAR</div>

这篇关于在contenteditable中替换特定单词的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆