如何在用户文本选择旁边放置元素?

vsy*_*ync 24 javascript dom

我需要在用户选择的文本旁边放置一个绝对定位按钮.就像IE8在内部做的那样.

我正在将一个jQuery mouseup事件绑定到Document,并获取所选文本,但我目前没有关于如何知道实际选择位置的想法,而没有将其包装在某个元素中,因为选择文本可以是跨越几个元素,如果我将其包裹起来会使结构混乱.

Tim*_*own 27

您可以在选区末尾放置标记范围,使用jQuery获取其坐标,将按钮放在这些坐标处并删除标记范围.

以下内容可以帮助您入门:

var markSelection = (function() {
    var markerTextChar = "\ufeff";
    var markerTextCharEntity = "";

    var markerEl, markerId = "sel_" + new Date().getTime() + "_" + Math.random().toString().substr(2);

    var selectionEl;

    return function(win) {
        win = win || window;
        var doc = win.document;
        var sel, range;
        // Branch for IE <= 8 
        if (doc.selection && doc.selection.createRange) {
            // Clone the TextRange and collapse
            range = doc.selection.createRange().duplicate();
            range.collapse(false);

            // Create the marker element containing a single invisible character by creating literal HTML and insert it
            range.pasteHTML('<span id="' + markerId + '" style="position: relative;">' + markerTextCharEntity + '</span>');
            markerEl = doc.getElementById(markerId);
        } else if (win.getSelection) {
            sel = win.getSelection();
            range = sel.getRangeAt(0).cloneRange();
            range.collapse(false);

            // Create the marker element containing a single invisible character using DOM methods and insert it
            markerEl = doc.createElement("span");
            markerEl.id = markerId;
            markerEl.appendChild( doc.createTextNode(markerTextChar) );
            range.insertNode(markerEl);
        }

        if (markerEl) {
            // Lazily create element to be placed next to the selection
            if (!selectionEl) {
                selectionEl = doc.createElement("div");
                selectionEl.style.border = "solid darkblue 1px";
                selectionEl.style.backgroundColor = "lightgoldenrodyellow";
                selectionEl.innerHTML = "&lt;- selection";
                selectionEl.style.position = "absolute";

                doc.body.appendChild(selectionEl);
            }

            // Find markerEl position http://www.quirksmode.org/js/findpos.html
        var obj = markerEl;
        var left = 0, top = 0;
        do {
            left += obj.offsetLeft;
            top += obj.offsetTop;
        } while (obj = obj.offsetParent);

            // Move the button into place.
            // Substitute your jQuery stuff in here
            selectionEl.style.left = left + "px";
            selectionEl.style.top = top + "px";

            markerEl.parentNode.removeChild(markerEl);
        }
    };
})();
Run Code Online (Sandbox Code Playgroud)

  • 虽然不太可能,但可能存在依赖于某些元素顺序的 CSS 规则,例如“#example&gt;span+span”。将标记范围插入到内容中会破坏那些可能改变/破坏布局的规则。range.getBoundingClientRect() 可能是一个更强大的解决方案。 (2认同)

Ric*_*ick 15

当我需要内容保持不受干扰,同时在其附近放置其他内容时,我使用getBoundingClientRect().

    var r=window.getSelection().getRangeAt(0).getBoundingClientRect();
    var relative=document.body.parentNode.getBoundingClientRect();
    ele.style.top =(r.bottom -relative.top)+'px';//this will place ele below the selection
    ele.style.right=-(r.right-relative.right)+'px';//this will align the right edges together
Run Code Online (Sandbox Code Playgroud)

这适用于Chrome,但IE喜欢给出奇怪的东西,所以这是一个跨浏览器的解决方案:(在Chrome和IE中测试,可能在其他地方工作)

https://jsfiddle.net/joktrpkz/7/