Javascript 在包含 HTML 内容的 contentEditable 区域中获取插入符号(光标)位置

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4767848/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 13:59:28  来源:igfitidea点击:

Get caret (cursor) position in contentEditable area containing HTML content

javascriptwysiwygcontenteditablegetselection

提问by Frodik

I have contentEditable element (can be p, div, ...) and I would like to get caret (cursor) position in it. I can normally achieve it with this piece of code:

我有 contentEditable 元素(可以是 p、div、...),我想在其中获得插入符号(光标)位置。我通常可以用这段代码实现它:

var position = window.getSelection().getRangeAt(0).startOffset;

This works fine while the element contains just text. But when the element contains some HTML formatting, the returned position is relative to caret position within included HTML element.

当元素仅包含文本时,这可以正常工作。但是当元素包含一些 HTML 格式时,返回的位置是相对于包含的 HTML 元素中插入符号的位置。

Let's assume contents of contentEditable element is this:

让我们假设 contentEditable 元素的内容是这样的:

AB<b>CD</b>EF

If caret is inside <b></b>, let's say between C and D, the returned position with above code is 1 instead of 3 (counted from the begining of the contentEditable element's content)

如果 caret 在 inside <b></b>,比方说在 C 和 D 之间,上面代码的返回位置是 1 而不是 3(从 contentEditable 元素的内容开始计算)

Can anybody come up with solution to this ?

任何人都可以提出解决方案吗?

采纳答案by Tim Down

UPDATE

更新

I've written a simpler version of this that also works in IE < 9:

我写了一个更简单的版本,它也适用于 IE < 9:

https://stackoverflow.com/a/4812022/96100

https://stackoverflow.com/a/4812022/96100

Old Answer

旧答案

This is actually a more useful result than a character offset within the text of the whole document: the startOffsetproperty of a DOM Range (which is what window.getSelection().getRangeAt()returns) is an offset relative to its startContainerproperty (which isn't necessarily always a text node, by the way). However, if you really want a character offset, here's a function that will do it.

这实际上是一个比整个文档文本中的字符偏移更有用的结果:startOffsetDOM 范围的属性(window.getSelection().getRangeAt()返回的内容)是相对于其startContainer属性的偏移量(不一定总是文本节点,通过道路)。但是,如果你真的想要一个字符偏移,这里有一个函数可以做到。

Here's a live example: http://jsfiddle.net/timdown/2YcaX/

这是一个活生生的例子:http: //jsfiddle.net/timdown/2YcaX/

Here's the function:

这是函数:

function getCharacterOffsetWithin(range, node) {
    var treeWalker = document.createTreeWalker(
        node,
        NodeFilter.SHOW_TEXT,
        function(node) {
            var nodeRange = document.createRange();
            nodeRange.selectNode(node);
            return nodeRange.compareBoundaryPoints(Range.END_TO_END, range) < 1 ?
                NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT;
        },
        false
    );

    var charCount = 0;
    while (treeWalker.nextNode()) {
        charCount += treeWalker.currentNode.length;
    }
    if (range.startContainer.nodeType == 3) {
        charCount += range.startOffset;
    }
    return charCount;
}

回答by Andrea

This is a very old post, but still one of the first results searching on Google, so maybe still useful. This works for me to get right position considering html tags and newlines as well (tested on Firefox):

这是一篇很老的帖子,但仍然是在谷歌上搜索的第一个结果之一,所以也许仍然有用。这也适用于我考虑 html 标签和换行符(在 Firefox 上测试)的正确位置:

function getCaretPosition (node) {
    var range = window.getSelection().getRangeAt(0),
        preCaretRange = range.cloneRange(),
        caretPosition,
        tmp = document.createElement("div");

    preCaretRange.selectNodeContents(node);
    preCaretRange.setEnd(range.endContainer, range.endOffset);
    tmp.appendChild(preCaretRange.cloneContents());
    caretPosition = tmp.innerHTML.length;
    return caretPosition;
}

It uses the cloneContents functionality in order to get the actual html and appends the documentfragment to a temporary div in order to get the html length.

它使用 cloneContents 功能来获取实际的 html 并将文档片段附加到临时 div 以获取 html 长度。

回答by Antti

If you want to insert element then you could try to do something like this:

如果要插入元素,则可以尝试执行以下操作:

// Get range
var range = document.caretRangeFromPoint(event.clientX, event.clientY);
if (range)
  range.insertNode(elementWhichYouWantToAddToContentEditable);