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

发布于 2024-10-13 15:44:09 字数 457 浏览 9 评论 0原文

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

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

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

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

AB<b>CD</b>EF

如果插入符位于 内部,假设在 C 和 D 之间,则上述代码返回的位置是 1 而不是 3(已统计)从 contentEditable 元素的内容开始)

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

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:

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.

Let's assume contents of contentEditable element is this:

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)

Can anybody come up with solution to this ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冷了相思 2024-10-20 15:44:09

更新

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

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

旧答案

这实际上是一个比整个文档文本中的字符偏移量:DOM Range 的 startOffset 属性(即 window.getSelection().getRangeAt() 返回的内容)是相对偏移量到它的 startContainer 属性(顺便说一句,它不一定总是文本节点)。但是,如果您确实想要字符偏移量,这里有一个函数可以做到这一点。

这是一个实例: http://jsfiddle.net/timdown/2YcaX/

这是函数:

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;
}

UPDATE

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

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 startOffset property of a DOM Range (which is what window.getSelection().getRangeAt() returns) is an offset relative to its startContainer property (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.

Here's a live example: 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;
}
乖乖 2024-10-20 15:44:09

这是一篇非常古老的文章,但仍然是在谷歌上搜索的第一个结果之一,所以也许仍然有用。考虑到 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;
}

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

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):

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.

南…巷孤猫 2024-10-20 15:44:09

如果你想插入元素那么你可以尝试这样做:

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

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文