如何在contenteditable元素(div)中设置插入符(光标)的位置?

我有这个简单的HTML作为例子:

<div id="editable" contenteditable="true"> text text text<br> text text text<br> text text text<br> </div> <button id="button">focus</button> 

我想要简单的东西 – 当我点击按钮,我想把光标(光标)放在可编辑div的特定位置。 从网上搜索,我有这个JS附加到按钮点击,但它不工作(FF,铬):

 var range = document.createRange(); var myDiv = document.getElementById("editable"); range.setStart(myDiv, 5); range.setEnd(myDiv, 5); 

是否可以像这样设置手动插入位置?

在大多数浏览器中,您需要RangeSelection对象。 您将每个选择边界指定为该节点内的节点和偏移量。 例如,要将插入符号设置为第二行文本的第五个字符,您需要执行以下操作:

 var el = document.getElementById("editable"); var range = document.createRange(); var sel = window.getSelection(); range.setStart(el.childNodes[2], 5); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); 

IE <9完全不同。 如果您需要支持这些浏览器,则需要使用不同的代码。

jsFiddle例子: http : //jsfiddle.net/timdown/vXnCM/

大多数关于可以理解的游标定位的答案都相当简单,因为它们只能用简单的香草文本来处理输入。 一旦在容器中使用了html元素,输入的文本就会被分割成节点,并在树结构中自由分配。

要设置光标位置,我有这个函数循环所提供的节点中的所有子文本节点,并设置从初始节点的开始到chars.count字符的范围:

 function createRange(node, chars, range) { if (!range) { range = document.createRange() range.selectNode(node); range.setStart(node, 0); } if (chars.count === 0) { range.setEnd(node, chars.count); } else if (node && chars.count >0) { if (node.nodeType === Node.TEXT_NODE) { if (node.textContent.length < chars.count) { chars.count -= node.textContent.length; } else { range.setEnd(node, chars.count); chars.count = 0; } } else { for (var lp = 0; lp < node.childNodes.length; lp++) { range = createRange(node.childNodes[lp], chars, range); if (chars.count === 0) { break; } } } } return range; }; 

然后我用这个函数调用例程:

 function setCurrentCursorPosition(chars) { if (chars >= 0) { var selection = window.getSelection(); range = createRange(document.getElementById("test").parentNode, { count: chars }); if (range) { range.collapse(false); selection.removeAllRanges(); selection.addRange(range); } } }; 

range.collapse(false)将光标设置到范围的末尾。 我已经用最新版本的Chrome,IE,Mozilla和Opera进行了测试,它们都能正常工作。

PS。 如果有人感兴趣,我使用这个代码获取当前的光标位置:

 function isChildOf(node, parentId) { while (node !== null) { if (node.id === parentId) { return true; } node = node.parentNode; } return false; }; function getCurrentCursorPosition(parentId) { var selection = window.getSelection(), charCount = -1, node; if (selection.focusNode) { if (isChildOf(selection.focusNode, parentId)) { node = selection.focusNode; charCount = selection.focusOffset; while (node) { if (node.id === parentId) { break; } if (node.previousSibling) { node = node.previousSibling; charCount += node.textContent.length; } else { node = node.parentNode; if (node === null) { break } } } } } return charCount; }; 

代码与set函数相反 – 它获取当前的window.getSelection()。focusNode和focusOffset,并向后计数遇到的所有文本字符,直到它碰到id为containerId的父节点。 isChildOf函数只是在运行之前检查,suplied节点实际上是提供的parentId的子节点。

代码应该可以直接运行而不用更改,但是我刚刚从我开发的jQuery插件中取得了这个功能,所以已经破解了几个这样的东西 – 让我知道是否有任何东西不起作用!

(p)(span)等前置元素时,这是非常硬的插入符号。目标是获得(对象文本):

  <div id="editable" contenteditable="true">dddddddddddddddddddddddddddd<p>dd</p>psss<p>dd</p><p>dd</p> <p>text text text</p> </div> <p id='we'></p> <button onclick="set_mouse()">focus</button> <script> function set_mouse() { var as = document.getElementById("editable"); el=as.childNodes[1].childNodes[0];//goal is to get ('we') id to write (object Text) because it work only in object text var range = document.createRange(); var sel = window.getSelection(); range.setStart(el, 1); range.collapse(true); sel.removeAllRanges(); sel.addRange(range); document.getElementById("we").innerHTML=el;// see out put of we id } </script>