javascript用户选择突出显示

foo*_*bar 18 javascript highlight

我正在尝试使用javascript来突出显示用户在单击某个奇数突出显示按钮时选择的文本(如<span style ="background-color:yellow">突出显示的文本</ span>).它只需要与WebKit或Firefox一起使用,但它似乎几乎不可能,因为它必须在以下情况下工作:

<p>this is text</p>
<p>I eat food</p>
Run Code Online (Sandbox Code Playgroud)

当用户在浏览器中选择"is text"到"I eat"时(不能只是在那里放一个跨度).

这种情况:

<span><span>this is text</span>middle text<span>this is text</span></span>
Run Code Online (Sandbox Code Playgroud)

当用户在浏览器中选择"is text"到"this is"时(即使你可以在选择中的每个元素周围包含你的高亮显示,我希望你看到你试图让中间文本突出显示).

这个问题似乎没有在任何地方得到解决,坦率地说我怀疑这是可能的.

如果你可以从选择中得到的Range作为一个完整的html字符串,可以解析然后替换,这是可能的,但据我所知,你不能得到一个范围的原始html ..可怜.

und*_*dJD 50

这个答案对你来说可能要晚了几年,但是我遇到了类似的问题,想在这里记录下来,因为这是谷歌的第一次打击.

重申一下,问题是你想从用户选择中捕获Range对象并用样式化的div包围它,如下所示:

function highlightSelection() {
    var userSelection = window.getSelection().getRangeAt(0);
    highlightRange(userSelection);

}

function highlightRange(range) {
    var newNode = document.createElement("div");
    newNode.setAttribute(
       "style",
       "background-color: yellow; display: inline;"
    );
    range.surroundContents(newNode);
}
Run Code Online (Sandbox Code Playgroud)

但正如原始父母所说,这是不安全的.如果选择不跨越元素边界,它将起作用,但如果用户选择创建的范围是跨越HTML标记边界的不安全范围,则它将抛出DOM错误.


解决方案是生成一个较小的Range对象数组,这些对象都不是单独穿过元素屏障,而是共同覆盖用户选择的范围.这些安全范围中的每一个都可以如上突出显示.

function getSafeRanges(dangerous) {
    var a = dangerous.commonAncestorContainer;
    // Starts -- Work inward from the start, selecting the largest safe range
    var s = new Array(0), rs = new Array(0);
    if (dangerous.startContainer != a)
        for(var i = dangerous.startContainer; i != a; i = i.parentNode)
            s.push(i)
    ;
    if (0 < s.length) for(var i = 0; i < s.length; i++) {
        var xs = document.createRange();
        if (i) {
            xs.setStartAfter(s[i-1]);
            xs.setEndAfter(s[i].lastChild);
        }
        else {
            xs.setStart(s[i], dangerous.startOffset);
            xs.setEndAfter(
                (s[i].nodeType == Node.TEXT_NODE)
                ? s[i] : s[i].lastChild
            );
        }
        rs.push(xs);
    }

    // Ends -- basically the same code reversed
    var e = new Array(0), re = new Array(0);
    if (dangerous.endContainer != a)
        for(var i = dangerous.endContainer; i != a; i = i.parentNode)
            e.push(i)
    ;
    if (0 < e.length) for(var i = 0; i < e.length; i++) {
        var xe = document.createRange();
        if (i) {
            xe.setStartBefore(e[i].firstChild);
            xe.setEndBefore(e[i-1]);
        }
        else {
            xe.setStartBefore(
                (e[i].nodeType == Node.TEXT_NODE)
                ? e[i] : e[i].firstChild
            );
            xe.setEnd(e[i], dangerous.endOffset);
        }
        re.unshift(xe);
    }

    // Middle -- the uncaptured middle
    if ((0 < s.length) && (0 < e.length)) {
        var xm = document.createRange();
        xm.setStartAfter(s[s.length - 1]);
        xm.setEndBefore(e[e.length - 1]);
    }
    else {
        return [dangerous];
    }

    // Concat
    rs.push(xm);
    response = rs.concat(re);    

    // Send to Console
    return response;
}
Run Code Online (Sandbox Code Playgroud)

然后可以(似乎)突出显示用户选择,使用此修改后的代码:

function highlightSelection() {
    var userSelection = window.getSelection().getRangeAt(0);
    var safeRanges = getSafeRanges(userSelection);
    for (var i = 0; i < safeRanges.length; i++) {
        highlightRange(safeRanges[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,您可能需要一些更高级的CSS来使用户可以看起来很好的许多不同的元素.我希望最终这有助于互联网上的其他一些疲惫的灵魂!

  • 干得好,但是.. 这个解决方案的局限性是将一个整体分成几个部分,然后将这些部分分开。在按照用户期望(已创建)使用它们时,您还需要一个通用的类或属性查找来重新统一它们。 (2认同)
  • 非常感谢您为我们所有人解决了这个问题。这很好用。我要**强调**的一点是该函数返回一些空范围,从而创建了一些不必要的跨度元素。我在我的 highlightRange 函数中添加了一个额外的条件来避免这个问题。此条件跳过任何空范围。谢谢,如果 (range.toString() !== "" &amp;&amp; range.toString().match(/\w+/g) !== null) { } (2认同)

小智 8

好吧,你可以使用DOM操作来完成它.这适用于Firefox:

var selection = window.getSelection();
var range = selection.getRangeAt(0);
var newNode = document.createElement("span");
newNode.setAttribute("style", "background-color: pink;");
range.surroundContents(newNode); 
Run Code Online (Sandbox Code Playgroud)

似乎也适用于当前版本的Safari.请参阅https://developer.mozilla.org/en/DOM/range.surroundContentshttp://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/ranges.html

  • 如果选择跨越元素边界(例如,如果它跨越多个段落),则这不起作用. (5认同)

Muh*_*lal 8

这是一个完整的代码,用于突出显示和取消高亮显示文本

<!DOCTYPE html>
    <html>
        <head>
            <style type="text/css">
                .highlight
                {
                    background-color: yellow;
                }
                #test-text::-moz-selection { /* Code for Firefox */

                    background: yellow;
                }

                #test-text::selection {

                    background: yellow;
                }

            </style>
        </head>

        <body>
            <div id="div1" style="border: 1px solid #000;">
                <div id="test-text">
                    <h1> Hello How are you </h1>
                    <p >
                        Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.
                    </p>
                </div>
            </div>
            <br />

        </body>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
            <script type="text/javascript">
                mouseXPosition = 0;
                $(document).ready(function () {

                    $("#test-text").mousedown(function (e1) {
                        mouseXPosition = e1.pageX;//register the mouse down position
                    });

                    $("#test-text").mouseup(function (e2) {
                        var highlighted = false;
                        var selection = window.getSelection();
                        var selectedText = selection.toString();
                        var startPoint = window.getSelection().getRangeAt(0).startOffset;
                        var endPoint = window.getSelection().getRangeAt(0).endOffset;
                        var anchorTag = selection.anchorNode.parentNode;
                        var focusTag = selection.focusNode.parentNode;
                        if ((e2.pageX - mouseXPosition) < 0) {
                            focusTag = selection.anchorNode.parentNode;
                            anchorTag = selection.focusNode.parentNode;
                        }
                        if (selectedText.length === (endPoint - startPoint)) {
                            highlighted = true;

                            if (anchorTag.className !== "highlight") {
                                highlightSelection();
                            } else {
                                var afterText = selectedText + "<span class = 'highlight'>" + anchorTag.innerHTML.substr(endPoint) + "</span>";
                                anchorTag.innerHTML = anchorTag.innerHTML.substr(0, startPoint);
                                anchorTag.insertAdjacentHTML('afterend', afterText);
                            }

                        }else{
                            if(anchorTag.className !== "highlight" && focusTag.className !== "highlight"){
                                highlightSelection();  
                                highlighted = true;
                            }

                        }


                        if (anchorTag.className === "highlight" && focusTag.className === 'highlight' && !highlighted) {
                            highlighted = true;

                            var afterHtml = anchorTag.innerHTML.substr(startPoint);
                            var outerHtml = selectedText.substr(afterHtml.length, selectedText.length - endPoint - afterHtml.length);
                            var anchorInnerhtml = anchorTag.innerHTML.substr(0, startPoint);
                            var focusInnerHtml = focusTag.innerHTML.substr(endPoint);
                            var focusBeforeHtml = focusTag.innerHTML.substr(0, endPoint);
                            selection.deleteFromDocument();
                            anchorTag.innerHTML = anchorInnerhtml;
                            focusTag.innerHTml = focusInnerHtml;
                            var anchorafterHtml = afterHtml + outerHtml + focusBeforeHtml;
                            anchorTag.insertAdjacentHTML('afterend', anchorafterHtml);


                        }

                        if (anchorTag.className === "highlight" && !highlighted) {
                            highlighted = true;
                            var Innerhtml = anchorTag.innerHTML.substr(0, startPoint);
                            var afterHtml = anchorTag.innerHTML.substr(startPoint);
                            var outerHtml = selectedText.substr(afterHtml.length, selectedText.length);
                            selection.deleteFromDocument();
                            anchorTag.innerHTML = Innerhtml;
                            anchorTag.insertAdjacentHTML('afterend', afterHtml + outerHtml);
                         }

                        if (focusTag.className === 'highlight' && !highlighted) {
                            highlighted = true;
                            var beforeHtml = focusTag.innerHTML.substr(0, endPoint);
                            var outerHtml = selectedText.substr(0, selectedText.length - beforeHtml.length);
                            selection.deleteFromDocument();
                            focusTag.innerHTml = focusTag.innerHTML.substr(endPoint);
                            outerHtml += beforeHtml;
                            focusTag.insertAdjacentHTML('beforebegin', outerHtml );


                        }
                        if (!highlighted) {
                            highlightSelection();
                        }
                        $('.highlight').each(function(){
                            if($(this).html() == ''){
                                $(this).remove();
                            }
                        });
                        selection.removeAllRanges();
                    });
                });

                function highlightSelection() {
                    var selection;

                    //Get the selected stuff
                    if (window.getSelection)
                        selection = window.getSelection();
                    else if (typeof document.selection != "undefined")
                        selection = document.selection;

                    //Get a the selected content, in a range object
                    var range = selection.getRangeAt(0);

                    //If the range spans some text, and inside a tag, set its css class.
                    if (range && !selection.isCollapsed) {
                        if (selection.anchorNode.parentNode == selection.focusNode.parentNode) {
                            var span = document.createElement('span');
                            span.className = 'highlight';
                            span.textContent = selection.toString();
                            selection.deleteFromDocument();
                            range.insertNode(span);
    //                        range.surroundContents(span);
                        }
                    }
                }

            </script>
    </html>
Run Code Online (Sandbox Code Playgroud)

https://jsfiddle.net/Bilalchk123/1o4j0w2v/

  • 不适用于跨多个段落的文本选择。 (2认同)

小智 7

这是我第一次在这里发帖,但看看你的答案,不会有这样的工作吗?我在这里有一个示例:http: //henriquedonati.com/projects/Extension/extension.html

function highlightSelection() {
    var userSelection = window.getSelection();
    for(var i = 0; i < userSelection.rangeCount; i++) {
        highlightRange(userSelection.getRangeAt(i));
    }

}

function highlightRange(range) {
    var newNode = document.createElement("span");
    newNode.setAttribute(
       "style",
       "background-color: yellow; display: inline;"
    );
    range.surroundContents(newNode);
}
Run Code Online (Sandbox Code Playgroud)


foo*_*bar 6

    function load(){
      window.document.designMode = "On";
      //run this in a button, will highlight selected text
      window.document.execCommand("hiliteColor", false, "#768");
    }
   
Run Code Online (Sandbox Code Playgroud)
    <html>
    <head>

    </head>
    <body contentEditable="true" onload="load()">
      this is text
    </body>
    </html>
Run Code Online (Sandbox Code Playgroud)