selecting text by ignoring inner Elements of div t

2019-02-23 22:21发布

问题:

<html>
<body>
<script language="javascript">
function getSelectionHTML()
{
    var div = document.getElementById("myDiv");

    if (document.createRange) { 
        var textNode=div.firstChild;
        var rangeObj=document.createRange();
        rangeObj.setStart(textNode,0);
        rangeObj.setEnd(textNode,5);
        div .innerHTML = div .innerHTML.replace(rangeObj.toString(), '<span style="background-color: lime">'+rangeObj.toString()+'</span>')
    }
}
</script>
<div id="myDiv">
asdf as<b>dfas df asf asdf sdfjk  dvh a sjkh jhcdjkv</b> iof scjahjkv ahsjv hdjk biud fcsvjksdhf k

</div>
<form name="aform">
<input type="button" value="Get selection" onclick="getSelectionHTML()">
</body>
</html>

Ok. Let me explain -> getSelectionHTML() method is for selection of characters from 0 to 10. I am getting the values by "myDiv" id. but inner bold, italic & other tags are giving me trouble.

In simple words, I just want to make selection of first ten characters (& apply them span tag) which are in "myDiv" tag.

What exactly I am missing?

回答1:

You're trying to select e.g. character 1 to 10 of your text. But when using Range.setStart and .endStart, the first parameter is the text node containing your text. If you browse through the DOM with Firebug (or Web Inspector), you'll notice that character 10 of your text resides in another element (the <b> element), with its own text node.

BTW, you left out several required elements/tags, which can also be a source of errors.

My corrected version reads

<!DOCTYPE html>
<html>
<head>
  <title>Title element is required</title>
<body>
<script>
function getSelectionHTML()
{
    var div = document.getElementById("myDiv");
    var bEl = document.getElementById("bEl");

    if (document.createRange) {.
        var textNode=div.firstChild;
        var rangeObj=document.createRange();
        rangeObj.setStart(textNode,0);
        rangeObj.setEnd(bEl.firstChild,2);
        alert(rangeObj.toString());
//        div.innerHTML = div.innerHTML.replace(rangeObj.toString(), '<span style="background-color: lime">'+rangeObj.toString()+'</span>');
    }
}
</script>
<div id="myDiv">
asdf as<b id="bEl">dfas df asf asdf sdfjk  dvh a sjkh jhcdjkv</b> iof scjahjkv ahsjv hdjk biud fcsvjksdhf k
</div>
<form name="aform">
  <input type="button" value="Get selection" onclick="getSelectionHTML()">
</form>
</body>
</html>

Now rangeObj contains the selected text, but you can't simply insert a <span> element the way you tried, because elements can't be nested this way:

<span>asdf as<b>dfa</span>s df asf…


回答2:

This is much easier in IE using TextRange, which is based around characters, words and sentences rather than nodes and offsets. In non-IE browsers, you'll need to do tedious manual traversal of text nodes in the DOM. However, even if you were to do this to get the first ten text characters within your <div> (which would be "asdf asdfa"), your strategy is flawed because you're using a replacement on innerHTML, which would try and fail to find "asdf asdfa" (innerHTML would start with "asdf as<b>dfa", or possibly "asdf as<B>", depending on browser).

What I would suggest is doing the DOM traversal to find all text nodes within the <div> and surrounding the parts of the text nodes you need with <span>s, thus avoiding Ranges altogether and therefore making this work in all major browsers.