我正在制作一个Web应用程序来测试正则表达式。在输入正则表达式的地方有一个输入,在找到匹配项并加亮的地方输入一个可编辑的pre元素。

示例:假设正则表达式为ab,如果用户在pre元素中输入abcab,则正则表达式和文本都会发送到我实现的api中,该api返回

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>






并将此字符串设置为pre元素的innerHTML

每次用户编辑pre元素的内容时都会执行此操作(确切地说是keyup事件)。我遇到的问题(我希望您能解决)是,每次设置intterHTML时,都会将插入号放在开头,并且我希望将其放置在de用户输入的最后一个字符之后。关于如何知道插入标记的位置以及如何将其放置在所需位置的任何建议?
谢谢。

更新为了更好地理解...一个明确的案例:
正则表达式是ab,在contenteditable元素中,我们有:

    <span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>






然后我在第一个a和第一个b之间键入一个c,所以现在我们有了:

    acbc<span style='background-color: lightgreen'>ab</span>






此时,插入记号已返回到contenteditable元素的开头,应将其放置在我键入的c之后。这就是我要实现的目标,希望现在更加清楚。

更新2



function refreshInnerHtml() {
  document.getElementById('textInput').innerHTML = "<span style='background-color: lightgreen'>ab</span>c<span style='background-color: lightgreen'>ab</span>";
}

      <pre contenteditable onkeyup="refreshInnerHtml()" id="textInput" style="border: 1px solid black;" ></pre>

最佳答案

在这里这些功能的帮助下->

Add element before/after text selection

我创造了一些我想成为你的东西。
我基本上将一些临时标签放入当前光标所在的html中。然后渲染新的HTML,然后用data-cpos属性用span替换标记。然后我使用它重新选择光标。



var insertHtmlBeforeSelection, insertHtmlAfterSelection;

(function() {
    function createInserter(isBefore) {
        return function(html) {
            var sel, range, node;
            if (window.getSelection) {
                // IE9 and non-IE
                sel = window.getSelection();
                if (sel.getRangeAt && sel.rangeCount) {
                    range = window.getSelection().getRangeAt(0);

                    range.collapse(isBefore);

                    // Range.createContextualFragment() would be useful here but is
                    // non-standard and not supported in all browsers (IE9, for one)
                    var el = document.createElement("div");
                    el.innerHTML = html;
                    var frag = document.createDocumentFragment(), node, lastNode;
                    while ( (node = el.firstChild) ) {
                        lastNode = frag.appendChild(node);
                    }
                    range.insertNode(frag);
                }
            } else if (document.selection && document.selection.createRange) {
                // IE < 9
                range = document.selection.createRange();
                range.collapse(isBefore);
                range.pasteHTML(html);
            }
        }
    }

    insertHtmlBeforeSelection = createInserter(true);
    insertHtmlAfterSelection = createInserter(false);
})();




function refreshInnerHtml() {
  var
    tag_start = '⇷',  //lets use some unicode chars unlikely to ever use..
    tag_end = '⇸',
    sel = document.getSelection(),
    input = document.getElementById('textInput');

  //remove old data-cpos
  [].forEach.call(
    input.querySelectorAll('[data-cpos]'),
    function(e) { e.remove() });

  //insert the tags at current cursor position
  insertHtmlBeforeSelection(tag_start);
  insertHtmlAfterSelection(tag_end);

  //now do our replace
  let html = input.innerText.replace(/(ab)/g, '<span style="background-color: lightgreen">$1</span>');
  input.innerHTML = html.replace(tag_start,'<span data-cpos>').replace(tag_end,'</span>');

  //now put cursor back
  var e = input.querySelector('[data-cpos]');
  if (e) {
    var range = document.createRange();
    range.setStart(e, 0);
    range.setEnd(e, 0);
    sel.removeAllRanges();
    sel.addRange(range);
  }
}

refreshInnerHtml();

Type some text below, with the letters 'ab' somewhere within it. <br>

<pre contenteditable onkeyup="refreshInnerHtml()" id="textInput" style="border: 1px solid black;" >It's about time.. above and beyond</pre>

09-28 00:34