如何设置包含文本和元素节点组合的 contenteditable div 的插入符号位置

How to set caret position of a contenteditable div containing combination of text and element nodes

我的HTML:

<div id="text" contenteditable="true">abcd<img src="icon.gif"/>efgh</div>

我的 caret = 5; 所以我想将插入符号位置设置为紧跟在图像之后,因为图像被视为 1 个字符。

所以我写了这个代码:

var node = document.querySelector("div");
node.focus();
var textNode = node.firstChild;
var caret = 5; 
var range = document.createRange();
range.setStart(textNode, caret);
range.setEnd(textNode, caret);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);

但是我得到这个错误:

Uncaught DOMException: Failed to execute 'setStart' on 'Range': The offset 5 is larger than or equal to the node's length (4).

请建议我如何实现这一目标?我可能在我想要的插入符位置之前有几张图片,每张图片都将被视为 1 个字符。

您的 textNode 有 3 个子项(1 个文本、1 个元素、1 个文本),因此您不能只使用 firstChild.

您需要遍历 <div>childNodes 并跟踪 childNodenodeType 等于 Node.TEXT_NODE 的字符数(请参阅here 在 MDN 上)。如果字符数小于 caret 的值,您可以从 caret 中减去它并移动到下一个文本节点。

根据您的条件:

I desire and each image would be treated as 1 character

代码将从 caret 中减去 1,其中 nodeType == 1Node.ELEMENT_NODE

这是一个包含多个图标的代码示例:

var node = document.querySelector("div");
node.focus();
var caret = 24; 

var child;
var childNodeIndex = 0;
for(var i=0; i<node.childNodes.length; i++) {
  child = node.childNodes[i];
  // Node.ELEMENT_NODE == 1
  // Node.TEXT_NODE == 3
  if(child.nodeType == Node.TEXT_NODE) {
    // keep track of caret across text childNodes
    if(child.length <= caret) {
      caret -= child.length;
    } else {
      break;
    }
  } else if (child.nodeType == Node.ELEMENT_NODE) {
    // condition that 'each image would be treated as 1 character'
    if(caret > 0) {
      caret -= 1;
    } else {
     break;
    }
  };
  childNodeIndex += 1;
}

var textNode = node.childNodes[childNodeIndex];

// your original code continues here...
var range = document.createRange();
range.setStart(textNode, caret);
range.setEnd(textNode, caret);
var sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
<div id="text" contenteditable="true">a<img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/><img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/><img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/><img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/>b<img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/>cdefghijkl<img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/>mnopq<img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/>rst<img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/>uvw<img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/>xyz<img src="https://www.splitbrain.org/_static/ico/circular/ico/add.png"/></div>