2014-10-01 155 views
13

還有就是HTML這樣的:恢復光標位置改變CONTENTEDITABLE後

<div contenteditable="true" class="value research-form thumbnail"> 
Some text here 
</div> 

和DIV的內容應動態地突出了一些話,而用戶類型,例如製造類似:

<div contenteditable="true" class="value research-form thumbnail"> 
Some text here <span style="background-color: yellow">highlight</div> it 
</div> 
<script> 
    $(document).ready(function() { 
     var input = $('#textarea').on('input', function (event) { 
      var newText = input.text().replace('highlight', '<span style="background-color: yellow">highlight</div>'); 
      input.html($.parseHTML(newText)); 
     }); 
    }); 
</script> 

但是有一個問題:當我刷新div中的文本時,光標在輸入文本的開始處移動。

改變contenteditable值後,有什麼辦法恢復光標位置嗎?或者,也許還有其他方式來獲得相同的效果?

+1

嘗試保存光標位置(見http://stackoverflow.com/questions/4767848/get-caret-cursor-position-in-contenteditable-area-containing- html-content),然後在input.html(...)後面設置它(請參閱http://stackoverflow.com/questions/1181700/set-cursor-position-on-contenteditable-div)。 我認爲你在這裏還有其他問題:在你的例子中,每次編輯文本時,「高亮」單詞將被包裹在一個新的跨度中。在添加新跨度之前,可能應該用佔位符替換包裹的單詞,然後將佔位符替換回來。 – Qwerty 2014-10-01 10:52:17

+0

如果您的解決方案符合您的期望,則應將其添加爲答案並將其選中。 http://stackoverflow.com/help/self-answer – 2016-01-27 17:10:34

+0

@JasonSperske完成 – Tdm 2016-01-29 12:40:14

回答

8

我找到了解決方案。

下面是一個完整的代碼:

<div class="container" style="margin-top: 10px"> 

    <div class="thumbnail value" contenteditable="true"> 

    </div> 

</div> 

<script> 
    $(document).ready(function() { 
     function getCaretCharacterOffsetWithin(element) { 
      var caretOffset = 0; 
      var doc = element.ownerDocument || element.document; 
      var win = doc.defaultView || doc.parentWindow; 
      var sel; 
      if (typeof win.getSelection != "undefined") { 
       sel = win.getSelection(); 
       if (sel.rangeCount > 0) { 
        var range = win.getSelection().getRangeAt(0); 
        var preCaretRange = range.cloneRange(); 
        preCaretRange.selectNodeContents(element); 
        preCaretRange.setEnd(range.endContainer, range.endOffset); 
        caretOffset = preCaretRange.toString().length; 
       } 
      } else if ((sel = doc.selection) && sel.type != "Control") { 
       var textRange = sel.createRange(); 
       var preCaretTextRange = doc.body.createTextRange(); 
       preCaretTextRange.moveToElementText(element); 
       preCaretTextRange.setEndPoint("EndToEnd", textRange); 
       caretOffset = preCaretTextRange.text.length; 
      } 
      return caretOffset; 
     } 

     function setCaretPosition(element, offset) { 
      var range = document.createRange(); 
      var sel = window.getSelection(); 

      //select appropriate node 
      var currentNode = null; 
      var previousNode = null; 

      for (var i = 0; i < element.childNodes.length; i++) { 
       //save previous node 
       previousNode = currentNode; 

       //get current node 
       currentNode = element.childNodes[i]; 
       //if we get span or something else then we should get child node 
       while(currentNode.childNodes.length > 0){ 
        currentNode = currentNode.childNodes[0]; 
       } 

       //calc offset in current node 
       if (previousNode != null) { 
        offset -= previousNode.length; 
       } 
       //check whether current node has enough length 
       if (offset <= currentNode.length) { 
        break; 
       } 
      } 
      //move caret to specified offset 
      if (currentNode != null) { 
       range.setStart(currentNode, offset); 
       range.collapse(true); 
       sel.removeAllRanges(); 
       sel.addRange(range); 
      } 
     } 

     function onInput(event) { 
      var position = getCaretCharacterOffsetWithin(input.get(0)); 
      var text = input.text(); 
      text = text.replace(new RegExp('\\btest\\b', 'ig'), '<span style="background-color: yellow">test</span>'); 
      input.html($.parseHTML(text)); 
      setCaretPosition(input.get(0), position); 
     } 

     var input = $('.value').on('input',onInput); 

     //content should be updated manually to prevent aditional spaces 
     input.html('simple input test example'); 
     //trigger event 
     onInput(); 
    }); 
</script> 
+0

在您的特例中,這是一個很好的解決方案:如果您在contentedtibales中禁用了新行。否則,獲取遊標偏移的腳本會忽略新線條實體,如
,並將光標位置設置在錯誤位置(在
元素之前)。 – 2017-08-02 21:01:49