首页 > 解决方案 > 当 HTML 在内容可编辑 DIV 中更新时,Vanilla JavaScript 可保存和恢复插入符号位置

问题描述

我知道在StackOverflowGoogle上有很多类似的问题的答案,我尝试了很多,但没有一个有效。所以我将在下面发布我自己的代码,希望有人可以提供帮助。提前致谢。

注意:当我手动输入此问题时,以下代码中可能存在拼写错误。如果他们让您感到困惑,我已经检查并为任何不便表示歉意。

我试图在该contenteditableDIV 中实现的逻辑:

  1. DIV 中的用户类型
  2. 同时,事件侦听器正在检查用户输入的文本并使用预定义的关键字数组进行过滤,例如['apple', 'banana']. 过滤后的文本将包装在 HTML 中并写回 DIV。
  3. 在实现上述目的的同时,用户不会丢失鼠标插入符号,这意味着此扫描和替换过程应该在后台不断发生,并且不会影响用户的编辑。

编码:

HTML(处理前)

<div id="editor">
    Mr Jenkins has an apple and a banana.
</div>

HTML(处理后)

<div id="editor">
    Mr Jenkins has an <u>apple</u> and a <u>banana</u>.
</div>

JavaScript(它在vue所以我在这里跳过了其他部分并在vanilla这里显示)

计划 A使用预定义的选择变量

这会引发错误“DOMException: Failed to execute 'collapse' on 'Selection': There is no child at offset 7"

// Global variable to store the offset value when DOM content loaded
// The input event of the #editor element is listened but skipped here
var caretPosition,
    selection = window.getSelection();

function scanText() {
    let editor = document.getElementById('editor');

    // Save the position
    caretPosition = selection.focusOffset;

    // Scan and replace text
    editor.innerHTML = filterText(); // Function filterText will return HTML as in above example

    // Restore the position
    selection.collapse(editor, caretPosition);
}

计划 B在旅途中使用获取选择

这不会引发任何错误,但插入符号位置很奇怪该focusOffset值远小于实际focusOffset值。例如,如果focusOffsetPlan A is 中100,它9Plan B中。所以它总是在错误的位置恢复

function scanText() {
    let editor = document.getElementById('editor');

    // Save the position
    caretPosition = window.getSelection().focusOffset;

    // Scan and replace text
    editor.innerHTML = filterText(); // Function filterText will return HTML as in above example

    // Restore the position
    window.getSelection().collapse(editor, caretPosition);
}

计划 C使用范围

“IndexSizeError:无法在 'Range' 上执行 'setStart':偏移 5 处没有子级。”

function scanText() {
    let editor = document.getElementById('editor'),
        offsets, range = new Range();

    // Save the range
    // It starts at 5 and ends at 101 though I only placed cursor at the end of the text
    if (window.getSelection().rangeCount) {
        offsets = [
            window.getSelection().getRangeAt(0).startOffset, // 5
            window.getSelection().getRangeAt(0).endOffset // 101
        ];
    }

    // Scan and replace text
    editor.innerHTML = filterText(); // Function filterText will return HTML as in above example

    // Restore the range
    range.setStart(editor, offsets[0]); // Set start container to editor and start offset as 5
    range.setEnd(editor, offsets[1]); // Set end container to editor and end offset as 101
}

标签: javascriptselectioncaret

解决方案


推荐阅读