如何设置包含文本和元素节点组合的 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
并跟踪 childNode
的 nodeType
等于 Node.TEXT_NODE
的字符数(请参阅here 在 MDN 上)。如果字符数小于 caret
的值,您可以从 caret
中减去它并移动到下一个文本节点。
根据您的条件:
I desire and each image would be treated as 1 character
代码将从 caret
中减去 1,其中 nodeType == 1
即 Node.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>
我的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
并跟踪 childNode
的 nodeType
等于 Node.TEXT_NODE
的字符数(请参阅here 在 MDN 上)。如果字符数小于 caret
的值,您可以从 caret
中减去它并移动到下一个文本节点。
根据您的条件:
I desire and each image would be treated as 1 character
代码将从 caret
中减去 1,其中 nodeType == 1
即 Node.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>