如何使用 html 子元素获取 contenteditable div 中的插入符位置?

发布于 2024-11-06 08:59:58 字数 1882 浏览 4 评论 0原文

我正在使用一个 contenteditable div,它可以选择在文本流中包含内联 html 元素,例如标签。

在某些时候,我需要获取插入符号位置,但发现在示例代码中,如果插入符号位于 html 子元素之后,则返回的位置不正确。

我需要一个跨浏览器解决方案,它允许我存储插入符号的位置,以便即使文本流中存在 html 元素,也可以在瞬间恢复它。

示例:

function getCaretPosition(editableDiv) {
    var caretPos = 0, containerEl = null, sel, range;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount) {
            range = sel.getRangeAt(0);
            if (range.commonAncestorContainer.parentNode == editableDiv) {
                caretPos = range.endOffset;
            }
        }
    } else if (document.selection && document.selection.createRange) {
        range = document.selection.createRange();
        if (range.parentElement() == editableDiv) {
            var tempEl = document.createElement("span");
            editableDiv.insertBefore(tempEl, editableDiv.firstChild);
            var tempRange = range.duplicate();
            tempRange.moveToElementText(tempEl);
            tempRange.setEndPoint("EndToEnd", range);
            caretPos = tempRange.text.length;
        }
    }
    return caretPos;
}

$('div').keyup(function(){
   alert(getCaretPosition(this));
});
div{width:300px; height:100px; border:solid 1px #DDD;}
div a{background:#333; color:#FFF;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<div contenteditable=true>
    some example text <a>anchor tag</a>&nbsp;
</div>

原始 JSFiddle: http://jsfiddle.net/wPYMR/2/

I am working with a contenteditable div that will have the option to have inline html elements such as tags in the text flow.

At certain points I need to grab the caret position but have found that with the example code the position returned is incorrect if the caret is after an html child element.

I need a cross browser solution that will allow me to store the position of the caret so that it can be restored a split second later even with the presence of html elements in the text flow.

Example:

function getCaretPosition(editableDiv) {
    var caretPos = 0, containerEl = null, sel, range;
    if (window.getSelection) {
        sel = window.getSelection();
        if (sel.rangeCount) {
            range = sel.getRangeAt(0);
            if (range.commonAncestorContainer.parentNode == editableDiv) {
                caretPos = range.endOffset;
            }
        }
    } else if (document.selection && document.selection.createRange) {
        range = document.selection.createRange();
        if (range.parentElement() == editableDiv) {
            var tempEl = document.createElement("span");
            editableDiv.insertBefore(tempEl, editableDiv.firstChild);
            var tempRange = range.duplicate();
            tempRange.moveToElementText(tempEl);
            tempRange.setEndPoint("EndToEnd", range);
            caretPos = tempRange.text.length;
        }
    }
    return caretPos;
}

$('div').keyup(function(){
   alert(getCaretPosition(this));
});
div{width:300px; height:100px; border:solid 1px #DDD;}
div a{background:#333; color:#FFF;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<div contenteditable=true>
    some example text <a>anchor tag</a> 
</div>

Original JSFiddle: http://jsfiddle.net/wPYMR/2/

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

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

发布评论

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

评论(2

允世 2024-11-13 08:59:58

我在这里回答了一个非常类似的问题: 在 IE 中编辑 Iframe 内容 - 维护文本选择的问题

这是该答案的一个稍微简化的版本:

如果您不更改 contenteditable 元素的内容,则可以使用以下函数。在执行任何您需要执行的操作之前调用 saveSelection(),然后调用 restoreSelection()。如果您要更改内容,我建议使用我的 Rangy 库的 保存/恢复选择模块

var saveSelection, restoreSelection;
if (window.getSelection) {
    // IE 9 and non-IE
    saveSelection = function() {
        var sel = window.getSelection(), ranges = [];
        if (sel.rangeCount) {
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                ranges.push(sel.getRangeAt(i));
            }
        }
        return ranges;
    };

    restoreSelection = function(savedSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
        for (var i = 0, len = savedSelection.length; i < len; ++i) {
            sel.addRange(savedSelection[i]);
        }
    };
} else if (document.selection && document.selection.createRange) {
    // IE <= 8
    saveSelection = function() {
        var sel = document.selection;
        return (sel.type != "None") ? sel.createRange() : null;
    };

    restoreSelection = function(savedSelection) {
        if (savedSelection) {
            savedSelection.select();
        }
    };
}

使用示例:

var sel = saveSelection();
// Do stuff here
restoreSelection(sel);

I've answered a very similar question here: Editing Iframe Content in IE - problem in maintaining text selection

Here's a slightly simplified version of that answer:

If you're not changing the contents of the contenteditable element then the following functions will do. Call saveSelection() before doing whatever you need to do and restoreSelection() afterwards. If you are changing the content, I'd suggest using my Rangy library's save/restore selection module.

var saveSelection, restoreSelection;
if (window.getSelection) {
    // IE 9 and non-IE
    saveSelection = function() {
        var sel = window.getSelection(), ranges = [];
        if (sel.rangeCount) {
            for (var i = 0, len = sel.rangeCount; i < len; ++i) {
                ranges.push(sel.getRangeAt(i));
            }
        }
        return ranges;
    };

    restoreSelection = function(savedSelection) {
        var sel = window.getSelection();
        sel.removeAllRanges();
        for (var i = 0, len = savedSelection.length; i < len; ++i) {
            sel.addRange(savedSelection[i]);
        }
    };
} else if (document.selection && document.selection.createRange) {
    // IE <= 8
    saveSelection = function() {
        var sel = document.selection;
        return (sel.type != "None") ? sel.createRange() : null;
    };

    restoreSelection = function(savedSelection) {
        if (savedSelection) {
            savedSelection.select();
        }
    };
}

Example use:

var sel = saveSelection();
// Do stuff here
restoreSelection(sel);
滴情不沾 2024-11-13 08:59:58
        var display = $("#autocomplete");
        var editArea = $('#editArea');    
        console.log(e.target.selectionStart);           
        var pos = $("#editArea").caret();
        var offset = editArea.offset();
        // now you can use left, top(they are relative position)
        display.css({
            left: offset.left + 10,
            top:  offset.top + 13,
            color : "#449"
        })
        display.toggleClass("show");
        return false;
        var display = $("#autocomplete");
        var editArea = $('#editArea');    
        console.log(e.target.selectionStart);           
        var pos = $("#editArea").caret();
        var offset = editArea.offset();
        // now you can use left, top(they are relative position)
        display.css({
            left: offset.left + 10,
            top:  offset.top + 13,
            color : "#449"
        })
        display.toggleClass("show");
        return false;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文