1.理解Range物件
重新來學習下HTML5中的Range物件和Selection物件,最近在維護富文字編輯器,感覺這方面的知識點很有用,所以趁著週末多學習下~
什麼是Range物件?
在HTML5中,一個Range物件代表頁面上的一段連續區域。可以通過如下語句建立一個空的Range物件。如下程式碼:
var range = document.createRange();
什麼是Selection物件?
在HTML5中,每一個瀏覽器視窗都有一個Selection物件,代表使用者滑鼠在頁面中所選取的區域。可以通過如下程式碼得到一個Selection物件:
var selection = window.getSelection(); 或 var selection = document.getSelection();
Selection物件與Range物件的區別是?
每一個Selection物件都有一個或多個Range物件,每一個Range物件代表使用者用滑鼠所選取範圍內的一段連續區域。
Firefox 與 chrome,safari對Selection的區別?
在Firefox瀏覽器中,使用者可以通過按住 ctrl鍵來選取頁面上的多個區域,因此一個Selection物件可能有多個Range物件。
在chrome或safari瀏覽器中,使用者每次只能選取一段區域,所以一個Selection物件中只能有一個Range物件。
如何獲取Selection物件中的某個Range物件呢?
可以通過Selection物件的getRangeAt方法來獲取。程式碼如下:
var range = document.getSelection().getRangeAt(rangeIndex);
rangeIndex 代表Range物件的序號,在chrome或safari中,使用者每次只能選取一段區域,因此該值只能為0;
如何判斷使用者是否選取了內容?
可以通過Selection物件的 rangeCount 屬性來判斷;
1. 使用者沒有按下滑鼠該屬性值為0;
2. 使用者按下滑鼠之後該屬性值為1;
3. 使用者用滑鼠加ctrl鍵選取了一個或多個區域時,該屬性值代表使用者通過滑鼠選取的區域的數量,當使用者取消該區域的選取之後,該屬性值為1.
下面是一個demo;頁面上顯示一段文字和一個按鈕,當使用者單擊按鈕時彈出的提示框中顯示使用者用滑鼠加ctrl鍵共選取了多少個區域及每一段區域中的內容。程式碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <h3>Selection物件與Range物件使用demo</h3> <input type="button" value="選中我然後點選" onClick="rangeTest()" /> <div id="showRange"></div> <script> function rangeTest() { var html, showRangeDiv=document.getElementById('showRange'), selection=document.getSelection(); if(selection.rangeCount > 0) { html = "您選取了"+ selection.rangeCount + "段內容<br/>"; for(var i = 0; i < selection.rangeCount; i++) { var range = selection.getRangeAt(i); html += "第"+ (i+1) + "段內容為:" + range + "<br/>"; } showRangeDiv.innerHTML = html; } } </script> </body> </html>
1-2 Range物件的屬性有哪些?
我們在頁面上建立的程式碼如下:
var rangeObj = document.createRange(); console.log(rangeObj);
列印後看到有如下屬性:
collapsed: (Boolean) 用於判斷Range物件所代表的區域的開始點和結束點是否位於相同的位置,如果相同該屬性值為true。
commonAncestorContainer: (node) 返回Range物件所代表的區域位於什麼節點之中。
endContainer: (node) 用於返回Range物件所代表的區域的終點位於什麼節點之中。
endOffset(int) 用於返回Range物件所代表區域的終點與包含該終點的節點起點之間的距離。
startContainer: (node) 用於返回Range物件所代表區域的起點位於什麼節點之中。
startOffset (int) 用於返回Range物件所代表的區域的起點與包含該起點節點的起點之間的距離。
2 Range物件的方法
2-1 理解使用 selectNode, selectNodeContents, 與 deleteContents方法
selectNode: Range物件的selectNode 方法用於將Range物件的起點指定為某個節點的起點,將Range物件的終點指定為該節點的終點。Range物件所代表的區域包含該節點。
使用方法如下:
rangeObj.selectNode(node);
demo舉例理解:
假如頁面上有一個div,該div包含內容,如果使用 rangeObj.selectNode("div"); 的含義是,選擇該div內的所有內容,包括該div標籤本身。
selectNodeContents: 該方法用於將Range物件的起點指定為某個節點中的所有內容的起點,將Range物件的終點指定為該節點所有內容的終點,也就是說使Range物件所代表的區域包含該節點的所有內容,但是不包括該節點標籤本身。
使用方法如下:
rangeObj.selectNodeContents(node);
demo舉例理解:
還是上面的div元素,該元素包含內容,如果使用 rangeObj.selectNodeContents('div');的話,的含義是,選擇該div內的所有內容,但是不包括該div本身。
deleteContents: 該方法用於將Range物件中所包含的內容從頁面中刪除。
使用方法如下:
rangeObj.deleteContents();
下面是使用一個demo來理解上面的三個方法的具體含義,頁面中有一個div元素,一個刪除內容的按鈕,和一個刪除元素的按鈕,div元素中顯示一些文字,當使用者單擊 "刪除內容"按鈕時,會將div元素中的文字從頁面中刪除,單擊 “刪除元素” 按鈕時,會將整個div元素從頁面中刪除。
程式碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <h3>Selection物件與Range物件使用demo</h3> <div id="div" style="background-color: #e0a0b0; width:300px; height: 50px;">aaaaadsadsdasadsbbgg</div> <button onclick="deleteRangeContents(true);">刪除內容</button> <button onclick="deleteRangeContents(false);">刪除元素</button> <script> function deleteRangeContents(flag) { var div = document.getElementById("div"); var rangeObj = document.createRange(); if (flag) { rangeObj.selectNodeContents(div); } else { rangeObj.selectNode(div); } rangeObj.deleteContents(); } </script> </body> </html>
2-2 理解使用 setStart方法,setEnd方法,setStartBefore方法,setStartAfter方法,setEndBefore方法與setEndAfter方法;
setStart: 該方法用於將某個節點中的某個位置指定為Range物件所代表區域的起點位置。使用方法如下:
rangeObj.setStart(node, num);
num的含義是:首先它是一個整型數值,有兩種含義取決於node節點;
1. 當第一個引數node所代表的節點是一個內容為一段文字的時候,那麼該引數值用於指定將第幾個文字結束位置作為Range物件所代表區域的起點位置(num是從0開始)
2. 當第一個引數node所代表的節點包括其他子節點時,該引數用於指定將第幾個子節點的結束位置作為Range物件所代表區域的起點位置。
setEnd: 該方法用於將某個節點中的某處位置指定為Range物件所代表區域的結束位置。使用方法如下:
rangeObj.setEnd(node, num);
num的含義: 首先是一個整型數值;
1. 當第一個引數node所代表的節點是一個內容為一段文字的時候,該引數指定將第幾個文字結束位置作為Range物件所代表區域的結束位置。
2. 當第一個引數node所代表的節點包括其他子節點時,該引數值用於指定將第幾個子節點的結束位置作為Range物件所代表區域的結束位置。
下面是一個簡單的demo來理解上面的 setStart和setEnd方法的使用,頁面上有一個div元素和一個刪除文字的按鈕,div元素中有一些文字,當使用者點選 刪除文字按鈕時,div元素中的第三個文字到第十個文字將被刪除。
程式碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <div id="myDiv" style="color: red">這段文字中第三個文字到第十個文字將被刪除</div> <button onclick="deleteChar()">刪除文字</button> <script> function deleteChar() { var div = document.getElementById("myDiv"); var textNode = div.firstChild; var rangeObj = document.createRange(); rangeObj.setStart(textNode, 2); rangeObj.setEnd(textNode, 10); rangeObj.deleteContents(); } </script> </body> </html>
setStartBefore: 該方法用於將某個節點的起始位置指定為Range物件所代表區域的起點位置。使用方法如下:
rangeObj.setStartBefore(node);
setStartAfter: 該方法用於將某個節點的終點位置指定為Range物件所代表區域的起點位置。使用方法如下:
rangeObj.setStartAfter(node);
setEndBefore: 該方法用於將某個節點的起始位置指定為Range物件所代表區域的終點位置,使用方法如下:
rangeObj.setEndBefore(node);
setEndAfter: 該方法用於將某個節點的終點位置指定為Range物件所代表區域的終點位置。使用方法如下:
rangeObj.setEndAfter(node);
看上面的四個方法容易混淆,我們來做一個demo,使用一下 setStartBefore 和 setEndAfter方法。 頁面上有一個表格和一個按鈕,使用者單擊按鈕時,通過Range物件的setStartBefore 和 setEndAfter方法 使Range物件代表的區域包含表格的第一行,然後刪除該行。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <table id="myTable" border="1" cellspacing="0" cellpadding="0"> <tr> <td>第一行第一列</td> <td>第一行第二列</td> </tr> <tr> <td>第二行第一列</td> <td>第二行第二列</td> </tr> </table> <button onclick="deleteFirstRow()">刪除第一行</button> <script> function deleteFirstRow() { var myTable = document.getElementById('myTable'); if (myTable.rows.length > 0) { var row = myTable.rows[0]; var rangeObj = document.createRange(); rangeObj.setStartBefore(row); rangeObj.setEndAfter(row); rangeObj.deleteContents(); } } </script> </body> </html>
2-3 理解使用 cloneRange方法,cloneContents方法,extractContents方法
cloneRange: 該方法用於對當前的Range物件進行復制,該方法返回複製的Range物件。使用方法如下:
var rangeClone = rangeObj.cloneRange();
下面可以看一個demo來理解一下,頁面上顯示一個 "克隆Range物件" 按鈕,使用者單擊該按鈕時,建立一個Range物件,該物件包含頁面中的所有內容,然後使用cloneRange方法複製Range物件,然後在彈窗顯示該Range物件中的內容。
程式碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <button onclick="cloneRange()">克隆Range物件</button> <script> function cloneRange() { var rangeObj = document.createRange(); rangeObj.selectNodeContents(document.body); var rangeClone = rangeObj.cloneRange(); console.log(rangeClone); alert(rangeClone.toString()); } </script> </body> </html>
cloneContents: 該方法用於在頁面上追加一段HTML程式碼,使用方法如下:
var docFragment = rangeObj.cloneContents();
該方法返回的是 一個 DocumentFragment物件,該物件為一個容器元素,當需要追加,修改,刪除或查詢頁面上的元素時,該方法非常有用。
下面是一個demo,頁面上顯示一個div元素,div元素中包含一些文字和一個按鈕,使用者點選按鈕時將在該div元素底部克隆出相同的文字和按鈕。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <div id="div"> <span>aaaaaa</span> <button onclick="cloneDivContent()">克隆</button> </div> <script> function cloneDivContent() { var div = document.getElementById('div'); var rangeObj = document.createRange(); rangeObj.selectNodeContents(div); var documentFragment = rangeObj.cloneContents(); div.appendChild(documentFragment); } </script> </body> </html>
extraContents: 該方法用於將Range物件所代表區域的HTML程式碼克隆到一個 DocumentFragment中,然後從頁面中刪除這段HTML程式碼;
使用方法如下:
var documentFragment = rangeObj.extraContents();
下面是一個demo, 頁面上有2個div元素和一個按鈕,其中第一個div元素包含一些文字,使用者單擊該按鈕時,把文字移動到第二個div中。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <div id="srcDiv" style="background-color: red; width: 300px; height:50px">adsddasdssdsdsdsads</div> <div id="distDiv" style="background-color: blue; width: 300px; height: 50px;"></div> <button onclick="moveContent()">移動元素內容</button> <script> function moveContent() { var srcDiv = document.getElementById('srcDiv'); var distDiv = document.getElementById("distDiv"); var rangeObj = document.createRange(); rangeObj.selectNodeContents(srcDiv); var documentFragment = rangeObj.extractContents(); distDiv.appendChild(documentFragment); } </script> </body> </html>
2-4 insertNode方法
該方法用於將指定的節點插入到某個Range物件所代表的區域中,插入位置為Range物件所代表區域的起點位置,如果該節點已經存在於頁面之中,那麼該節點
將被移動到Range物件所代表區域的起點處。
使用方法如下:
rangeObj.insertNode(node)
下面是一個demo,頁面中有一個div元素和一個按鈕,div元素有一些文字,在div元素中按下滑鼠左鍵時,該按鈕將被移動到按下滑鼠左鍵的位置。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <div onmouseup="moveButton()" style="width: 400px; background-color: red;">adssdasddsdasszczxccxzcx</div> <button id="button">按鈕</button> <script> function moveButton() { var button = document.getElementById("button"); var selection = document.getSelection(); if (selection.rangeCount > 0) { var range = selection.getRangeAt(0); range.insertNode(button); } } </script> </body> </html>
2-5 理解collapse方法 和 detach方法
該方法用於將Range物件所代表的區域的終點移動到該區域的起點處,或將Range物件所代表的區域的起點移動到終點處,使Range物件所代表的區域內不包含任何內容。
使用方法如下:
RangeObj.collapse(toStart);
引數toStart,是一個Boolean型,如果為false的話,表示將Range物件所代表的區域的起點移動到終點處,當為true的話,表示將Range物件所代表的區域的終點移動到該區域的起點處。
下面是一個demo,可以來理解下 collapse方法的使用;
頁面上有一個div元素,裡面包含一些文字,一個 選擇元素的 按鈕,一個 取消選擇元素的按鈕,和一個 顯示Range內容的按鈕,使用者單擊 選擇元素 按鈕時該Range物件中將包含頁面中的div元素,然後單擊 顯示Range內容按鈕 就彈出 該div元素的內容,再單擊 取消選擇按鈕 將使用Range物件的collapse方法清空Range物件的內容。再次單擊 顯示Range內容,將顯示空字串。
程式碼如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" name="viewport"> <title>標題</title> </head> <body> <div id="div" style="background-color: red; width:300px; height: 50px;">元素中的內容</div> <button onclick="selectRangeContents()">選擇元素</button> <button onclick="unselect()">取消選擇</button> <button onclick="showRange()">顯示Range內容</button> <script> var rangeObj = document.createRange(); function selectRangeContents() { var div = document.getElementById('div'); rangeObj.selectNode(div); } function unselect() { rangeObj.collapse(false); } function showRange() { alert(rangeObj.toString()); } </script> </body> </html>
detach方法: 該方法用於從瀏覽器中釋放Range物件,釋放之後將不能再訪問該Range物件,否則將丟擲指令碼錯誤,使用方法如下:
RangeObj.detach();