html5之Range對象詳解

一:Range對象的概念

Range對象代表頁面上一段連續(xù)的區(qū)域,通過Range對象可以獲取或者修改頁面上任何區(qū)域的內(nèi)容。也可以通過Range的方法進(jìn)行復(fù)制和移動頁面任何區(qū)域的元素。
在Js的document文檔中有一個方法用來創(chuàng)建一個Range對象,代碼如下:

var  range = document.createRange();

在html5中,每一個瀏覽器窗口都會有一個selection對象,代表用戶鼠標(biāo)在頁面中所選取的區(qū)域,(注意:經(jīng)過測試IE9以下的瀏覽器不支持Selection對象), 可以通過如下語句創(chuàng)建selection對象;

var  selection = document.getSelection();   
或者
var  selection  = window.getSelection();

每一個selection對象都有一個或者多個Range對象,每一個range對象代表用戶鼠標(biāo)所選取范圍內(nèi)的一段連續(xù)區(qū)域,在firefox中,可以通過ctrl鍵可以選取多個連續(xù)的區(qū)域,因此在firefox中一個selection對象有多個range對象,在其他瀏覽器中,用戶只能選取一段連續(xù)的區(qū)域,因此只有一個range對象。
可以通過selection對象的getRangeAt方法來獲取selection對象的某個Range對象,如下:
getRangeAt方法有一個參數(shù)index,代表該Range對象的序列號;我們可以通過Selection對象的rangeCount參數(shù)的值判斷用戶是否選取了內(nèi)容;
1.當(dāng)用戶沒有按下鼠標(biāo)時候,該參數(shù)的值為0.
2.當(dāng)用戶按下鼠標(biāo)的時候,該參數(shù)值為1.
3.當(dāng)用戶使用鼠標(biāo)同時按住ctrl鍵時選取了一個或者多個區(qū)域時候,該參數(shù)值代表用戶選取區(qū)域的數(shù)量。
4.當(dāng)用戶取消區(qū)域的選取時,該屬性值為1,代表頁面上存在一個空的Range對象;
測試代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>meter</title>
</head>
<body>
    <script>
       function rangeTest() {
            var  html,
            showRangeDiv = document.getElementById("showRange"),
             selection = document.getSelection();
            if(selection.rangeCount > 0) {
                html = "你選取了" + selection.rangeCount + "段內(nèi)容<br/>";
                for(var i = 0; i < selection.rangeCount; i++) {
                    var range = selection.getRangeAt(i);
                    html += "第" + (i + 1) + "段內(nèi)容為:" + range + "<br/>";
                }
                showRangeDiv.innerHTML = html;
            }
        }
    </script>
    <h3>selection對象與range對象的使用實例</h3>
    <input type="button" value="點擊我" onclick="rangeTest()"/>
    <div id="showRange"></div>
</body>
</html>

效果:


range_selection.png

二:Range對象的屬性和方法

(1)屬性

startContainer
包含“起點”的節(jié)點?!鞍钡囊馑际瞧瘘c所屬的節(jié)點。
endContainer
包含“結(jié)束點”的節(jié)點
startOffset
“起點”在startContainer中的偏移量。
如果startContainer是文本節(jié)點、注釋節(jié)點或CDATA節(jié)點,則返回“起點”在startContainer中字符偏移量。
如果startContainer是元素節(jié)點,則返回“起點”在startContainer.childNodes中的次序。

<p id="p1"><span>span</span><b id="b1">Hello</b> World</p>
<script type="text/javascript"> 
var oP1 = document.getElementById('p1') ;
var oB1 = document.getElementById('b1'); 
var oRange = document.createRange(); 
oRange.setStart(oB1.firstChild, 2); // 設(shè)置range的“起點” oRange.setEnd(oP1.lastChild, 3); // 設(shè)置range的“結(jié)束點” alert(oRange.startOffset); // 2,可看到“起點”在<b id="b1">Hello</b>應(yīng)是第三個字符。 
alert(oRange.startContainer); // 元素oB1.firstChild,文本節(jié)點</script>

collapsed:
起點和結(jié)束點在一起時為true;Range對象為空(剛createRange()時)也為true。
commonAncestorContainer
第一個包含Range的節(jié)點,同時包含起點和結(jié)束點。

(2)定位(設(shè)置“起點”和“結(jié)束點”)的一些方法

setStart(node, offset)和setEnd(node, offset)
setStart:設(shè)置起點的位置,node是對startContainer的引用,偏移則是startOffset;
setEnd:設(shè)置結(jié)束點的位置,node是對endContainer的引用,偏移則是startOffset;
代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>range3</title>
 <script>
  function deleteChar() {
      var div = document.getElementById("myDiv");
      var textNode = div.firstChild;
      var rangeObj = document.createRange();
      rangeObj.setStart(textNode,1);
     rangeObj.setEnd(textNode,4);
     rangeObj.deleteContents();
}
</script>
</head>
<body>
     <div id="myDiv" style="color:red">這段文字是用來刪除的</div>
     <button onclick="deleteChar()">刪除文字</button>
</body>
</html>

setStartBefore(referenceNode)、setStartAfter(referenceNode)
setEndBefore(referenceNode)、setEndAfter(referenceNode)

setStartBefore:將“起點”設(shè)置到referenceNode前
setStartAfter:將“起點”設(shè)置到referenceNode后
setEndBefore:將“結(jié)束點”設(shè)置到referenceNode前
setEndAfter:將“結(jié)束點”設(shè)置到referenceNode后
注意:使用這四個方法設(shè)置的“起點”或“結(jié)束點”的父節(jié)點與referenceNode的父節(jié)點是同一個元素。
代碼如下:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script type="application/javascript">
            function delrow(){
                var table=document.getElementById("mytable");
                if(table.rows.length>0){
                    var row=table.rows[0];
                    var rangeObj=document.createRange();
                    rangeObj.setStartBefore(row);
                    rangeObj.setEndAfter(row);
                    rangeObj.deleteContents();
                }
            }
        </script>
    </head>
    <body>
        <table id="mytable" border="1">
            <tr>
                <td>內(nèi)容1</td>
                <td>內(nèi)容2</td>
            </tr>
            <tr>
                <td>內(nèi)容3</td>
                <td>內(nèi)容4</td>
            </tr>
        </table>
        <button onclick="delrow()">刪除第一行</button>
    </body>
</html>

selectNode(referenceNode)和selectNodeContents(referenceNode)
selectNode:設(shè)置Range的范圍,包括referenceNode和它的所有后代(子孫)節(jié)點。
selectNodeContents:設(shè)置Range的范圍,包括它的所有后代節(jié)點。
二者的區(qū)別:

range_selection.png

(3)修改范圍的方法

cloneRange()
cloneRange()方法將返回一個當(dāng)前Range的副本,它也是Range對象。
注意它和cloneContents()的區(qū)別在于返回值不同,一個是HTML片段,一個是Range對象 。代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>meter</title>
</head>
<body>
    <p id="p">這里是隨便書寫的內(nèi)容</p>
    <button onclick="cloneRange()">克隆</button>
</body>
<script>
    function cloneRange() {
    var rangeObj = document.createRange();
    rangeObj.selectNodeContents(document.getElementById("p"));
    var rangeClone = rangeObj.cloneRange();
    alert(rangeClone.toString());
    }
</script>
</html>

cloneContents()
可以克隆選中Range的fragment并返回改fragment。這個方法類似extractContents(),但不是刪除,而是克隆。代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>meter</title>
</head>
<body>
     <p id="p">這里是隨便書寫的內(nèi)容</p>
     <button onclick="cloneContents()">克隆</button>
</body>
    <script>
         function cloneContents() {
             var rangeObj = document.createRange();
             rangeObj.selectNodeContents(document.getElementById("p"));
             var rangeClone = rangeObj.cloneContents();
             alert(rangeClone.toString());
         }
    </script>
</html>

deleteContents()
從Dom中刪除Range選中的fragment。注意該函數(shù)沒有返回值(實際上為undefined)。
代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>meter</title>
</head>
<body>
     <p id="p">這里是隨便書寫的內(nèi)容</p>
     <button onclick="delRange()">刪除</button>
</body>
    <script>
         function delRange() {
             var rangeObj = document.createRange();
             rangeObj.selectNodeContents(document.getElementById("p"));
             var rangeClone = rangeObj.deleteContents();             
         }
    </script>
</html>

extractContents()
將選中的Range從DOM樹中移到一個fragment中,并返回此fragment。代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>meter</title>
</head>
<body>
    <div id="srcDiv" style="background-color:aquamarine;width:300px;height:50px;">你好嗎?</div>
    <div id="distDiv" style="background-color:bisque;width:300px;height:50px"></div>
    <button onclick="moveContent()">移動元素</button>
</body>
<script>
    function moveContent() {
        var srcDiv = document.getElementById("srcDiv");
        var distDiv = document.getElementById("distDiv");
        var rangeObj = document.createRange();
        rangeObj.selectNodeContents(srcDiv);
        var docFrangMent = rangeObj.extractContents();
        distDiv.appendChild(docFrangMent);
    }
</script>
</html>

insertNode
insertNode方法可以插入一個節(jié)點到Range中,注意會插入到Range的“起點”。代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>meter</title>
</head>
<body>
    <p id="p1"><b>Hello</b> World</p>
</body>
<script>
    var oP1 = document.getElementById("p1");
    var oHello = oP1.firstChild.firstChild;
    var oWorld = oP1.lastChild;
    var oRange = document.createRange();
    var oSpan = document.createElement("span");
    oSpan.appendChild(document.createTextNode("Inserted text"));
    oRange.setStart(oHello, 2);
    oRange.setEnd(oWorld, 3);
    oRange.insertNode(oSpan);
</script>
</html>

compareBoundaryPoints()

var compare = comparerange.compareBoundaryPoints(how, sourceRange);

compare:返回1, 0, -1.(0為相等,1為時,comparerange在sourceRange之后,-1為comparerange在sourceRange之前)。
how:比較哪些邊界點,為常數(shù)。
Range.START_TO_START - 比較兩個 Range 節(jié)點的開始點
Range.END_TO_END - 比較兩個 Range 節(jié)點的結(jié)束點
Range.START_TO_END - 用 sourceRange 的開始點與當(dāng)前范圍的結(jié)束點比較
Range.END_TO_START - 用 sourceRange 的結(jié)束點與當(dāng)前范圍的開始點比較
sourceRange:個Range對象的邊界。
detach()
雖然GC(垃圾收集器)會將其收集,但用detach()釋放range對象是一個好習(xí)慣。語法為:oRange.detach();
toString()
返回該范圍表示的文檔區(qū)域的純文本內(nèi)容,不包含任何標(biāo)簽;

謝謝觀看,希望對您有幫助。一起學(xué)前端一起成長!(__) 嘻嘻……

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容