为什么使用innerHTML替换块的内容会阻止浏览器的默认行为?

zqdjd7g9  于 2023-05-05  发布在  其他
关注(0)|答案(1)|浏览(106)

我有contentitable div <div contenteditable="true" id="editable-div"></div>
我想使用这个脚本向这个块添加hashtag功能:

const editableDiv = document.getElementById('editable-div');
editableDiv.addEventListener('input', function (event) {
  let a = editableDiv.innerHTML;
  if (a.indexOf('#') !== -1) {
    event.preventDefault();
    const editableDiv = document.getElementById('editable-div');
    let a = editableDiv.innerHTML;
    // Save the current cursor position
    const selection = window.getSelection();
    const range = selection.getRangeAt(0);
    const startContainer = range.startContainer;
    const startOffset = range.startOffset;
    // Change the contents of the block
    a = a.replace(/#(\w+)/g, '<a href="#">#$1</a>');
    editableDiv.innerHTML = a;
    // Restore the cursor position
    const newRange = document.createRange();
    newRange.setStart(startContainer, startOffset);
    selection.removeAllRanges();
    selection.addRange(newRange);
  }
});
#editable-div { height:100px; background-color:grey; }
<div contenteditable="true" id="editable-div"></div>

为什么在更改块的内容后光标总是转到开头?如何解决这个问题?return();不管用。并且恢复光标位置不起作用。

oewdyzsn

oewdyzsn1#

在对editableDiv.innerHTML进行操作之后,<div>内部的文档对象模型将被重新构建,而原来的range.startContainer节点#text将不再存在。它已被替换为新的#text节点。
如果您确定<div>中的start容器的 * 位置 *,并在重建后将range start设置为 * 相应的 * 容器,则可以正常工作。在下面的简单示例中,位置只是<div>中的子元素的编号。但如果<div>的内容包含嵌套的HTML标记,则会变得更加复杂。

function f() {
  var div = event.target;
  var {
    startContainer,
    startOffset
  } = getSelection().getRangeAt(0);
  var pos = document.evaluate(
    "count(preceding-sibling::node())",
    startContainer, undefined, XPathResult.NUMBER_TYPE
  ).numberValue;
  div.innerHTML = div.innerHTML.toLowerCase();
  startContainer = document.evaluate(`node()[${pos + 1}]`,
    div, undefined, XPathResult.FIRST_ORDERED_NODE_TYPE
  ).singleNodeValue;
  getSelection().setPosition(startContainer, startOffset);
}
<div contenteditable oninput="f()">Above the line
  <hr>Below the line</div>

(而不是确定 * 位置 *,可以将所有文本放置在可以通过其id识别的元素(例如<span>)中。但这并不包括用户可以创建新元素的情况,例如,将<li>元素添加到列表中。

相关问题