如何在可内容编辑元素(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,Chrome):
const range = document.createRange();
const myDiv = document.getElementById("editable");
range.setStart(myDiv, 5);
range.setEnd(myDiv, 5);
是否可以像这样手动设置插入符位置?
I have this simple HTML as an example:
<div id="editable" contenteditable="true">
text text text<br>
text text text<br>
text text text<br>
</div>
<button id="button">focus</button>
I want simple thing - when I click the button, I want to place caret(cursor) into specific place in the editable div. From searching over the web, I have this JS attached to button click, but it doesn't work (FF, Chrome):
const range = document.createRange();
const myDiv = document.getElementById("editable");
range.setStart(myDiv, 5);
range.setEnd(myDiv, 5);
Is it possible to set manually caret position like this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
在大多数浏览器中,您需要
Range
和Selection
对象。您将每个选择边界指定为一个节点以及该节点内的偏移量。例如,要将插入符号设置为第二行文本的第五个字符,您可以执行以下操作:IE < 9 的工作方式完全不同。如果您需要支持这些浏览器,则需要不同的代码。
jsFiddle 示例: http://jsfiddle.net/timdown/vXnCM/
In most browsers, you need the
Range
andSelection
objects. You specify each of the selection boundaries as a node and an offset within that node. For example, to set the caret to the fifth character of the second line of text, you'd do the following:IE < 9 works completely differently. If you need to support these browsers, you'll need different code.
jsFiddle example: http://jsfiddle.net/timdown/vXnCM/
您在可内容编辑的光标定位上找到的大多数答案都相当简单,因为它们仅适用于纯文本的输入。一旦您在容器中使用 html 元素,输入的文本就会被分割成节点并在树结构中自由分布。
为了设置光标位置,我有一个函数,它循环提供的节点内的所有子文本节点,并设置从初始节点的开头到 chars.count 字符的范围:
然后我调用具有此函数的例程:
range.collapse(false) 将光标设置到范围的末尾。我已经用最新版本的 Chrome、IE、Mozilla 和 Opera 对其进行了测试,它们都运行良好。
附言。如果有人感兴趣,我可以使用以下代码获取当前光标位置:
该代码执行与 set 函数相反的操作 - 它获取当前 window.getSelection().focusNode 和 focusOffset 并向后计数遇到的所有文本字符,直到它到达父节点id 为containerId。 isChildOf 函数只是在运行之前检查所提供的节点实际上是所提供的parentId 的子节点。
代码应该无需更改即可直接工作,但我刚刚从我开发的 jQuery 插件中获取了它,因此已经破解了几个 this's - 如果有任何问题请告诉我!
Most answers you find on contenteditable cursor positioning are fairly simplistic in that they only cater for inputs with plain vanilla text. Once you using html elements within the container the text entered gets split into nodes and distributed liberally across a tree structure.
To set the cursor position I have this function which loops round all the child text nodes within the supplied node and sets a range from the start of the initial node to the chars.count character:
I then call the routine with this function:
The range.collapse(false) sets the cursor to the end of the range. I've tested it with the latest versions of Chrome, IE, Mozilla and Opera and they all work fine.
PS. If anyone is interested I get the current cursor position using this code:
The code does the opposite of the set function - it gets the current window.getSelection().focusNode and focusOffset and counts backwards all text characters encountered until it hits a parent node with id of containerId. The isChildOf function just checks before running that the suplied node is actually a child of the supplied parentId.
The code should work straight without change, but I have just taken it from a jQuery plugin I've developed so have hacked out a couple of this's - let me know if anything doesn't work!
我重构了@Liam的答案。我把它放在一个带有静态方法的类中,我让它的函数接收一个元素而不是 #id,以及其他一些小调整。
此代码特别适合修复您使用
制作的富文本框中的光标。在得到下面的代码之前,我被困在这个问题上好几天了。
编辑:他的答案和这个答案有一个涉及按回车键的错误。由于 Enter 不算一个字符,因此在按 Enter 后光标位置会变得混乱。如果我能够修复代码,我将更新我的答案。
edit2:省去很多麻烦,并确保您的
是
display: inline-block
。这修复了一些与 Chrome 在按 Enter 键时将而不是
相关的错误。如何使用
代码
I refactored @Liam's answer. I put it in a class with static methods, I made its functions receive an element instead of an #id, and some other small tweaks.
This code is particularly good for fixing the cursor in a rich text box that you might be making with
<div contenteditable="true">
. I was stuck on this for several days before arriving at the below code.edit: His answer and this answer have a bug involving hitting enter. Since enter doesn't count as a character, the cursor position gets messed up after hitting enter. If I am able to fix the code, I will update my answer.
edit2: Save yourself a lot of headaches and make sure your
<div contenteditable=true>
isdisplay: inline-block
. This fixes some bugs related to Chrome putting<div>
instead of<br>
when you press enter.How To Use
Code
我为我的简单文本编辑器做了这个。
与其他方法的区别:
usage
selection.ts
I made this for my simple text editor.
Differences from other methods:
usage
selection.ts
我正在编写一个语法荧光笔(和基本的代码编辑器),我需要知道如何自动输入单引号字符并将插入符号向后移动(就像现在的许多代码编辑器一样)。
这是我的解决方案的一个片段,感谢这个线程、MDN 文档和大量 moz 控制台的大量帮助。
这是在一个 contenteditable div 元素中,
我将其留在这里作为感谢,意识到已经有一个可接受的答案。
I'm writting a syntax highlighter (and basic code editor), and I needed to know how to auto-type a single quote char and move the caret back (like a lot of code editors nowadays).
Heres a snippet of my solution, thanks to much help from this thread, the MDN docs, and a lot of moz console watching..
This is in a contenteditable div element
I leave this here as a thanks, realizing there is already an accepted answer.
如果您不想使用 jQuery,您可以尝试以下方法:
editableDiv
您可编辑的元素,不要忘记为其设置一个id
。然后,您需要从元素中获取innerHTML
并剪掉所有刹车线。并且只需使用下一个参数设置折叠即可。If you don't want to use jQuery you can try this approach:
editableDiv
you editable element, don't forget to set anid
for it. Then you need to get yourinnerHTML
from the element and cut all brake lines. And just set collapse with next arguments.当您有像 (p) (span) 等高级元素时,很难将插入符号设置在正确的位置。目标是获得(对象文本):
It is very hard set caret in proper position when you have advance element like (p) (span) etc. The goal is to get (object text):
我已经阅读并尝试了这里的一些案例,只是将对我有用的内容放在这里,根据 dom 节点考虑一些细节:
I've readed and tried some cases from here and just put here what is working for me, considering some details according dom nodes:
我认为将插入符号设置到 contenteditable 元素中的某个位置并不简单。我为此编写了自己的代码。它绕过节点树计算剩余的字符数并在所需元素中设置插入符。我没有对这段代码进行太多测试。
我还编写了代码来获取当前插入符位置(未测试):
您还需要注意 range.startOffset 和 range.endOffset 包含文本节点的字符偏移量 (nodeType === 3) 和元素节点的子节点偏移量(节点类型 === 1)。 range.startContainer和range.endContainer可以引用树中任何级别的任何元素节点(当然它们也可以引用文本节点)。
I think it's not simple to set caret to some position in contenteditable element. I wrote my own code for this. It bypasses the node tree calcing how many characters left and sets caret in needed element. I didn't test this code much.
I also wrote code to get current caret position (didn't test):
You also need to be aware of range.startOffset and range.endOffset contain character offset for text nodes (nodeType === 3) and child node offset for element nodes (nodeType === 1). range.startContainer and range.endContainer may refer to any element node of any level in the tree (of course they also can refer to text nodes).
基于蒂姆·唐的回答,但它检查最后一个已知的“好”文本行。它将光标置于最后。
此外,我还可以递归/迭代地检查每个连续的最后一个子节点的最后一个子节点,以找到 DOM 中绝对最后一个“好”文本节点。
Based on Tim Down's answer, but it checks for the last known "good" text row. It places the cursor at the very end.
Furthermore, I could also recursively/iteratively check the last child of each consecutive last child to find the absolute last "good" text node in the DOM.