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鍵共選取了多少個區域及每一段區域中的內容。代碼如下:
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
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元素從頁面中刪除。
代碼如下:
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
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元素中的第三個文字到第十個文字將被刪除。
代碼如下:
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
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對象代表的區域包含表格的第一行,然後刪除該行。
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
2-3 理解使用 cloneRange方法,cloneContents方法,extractContents方法
cloneRange: 該方法用於對當前的Range對象進行復制,該方法返回複製的Range對象。使用方法如下:
var rangeClone = rangeObj.cloneRange();
下面可以看一個demo來理解一下,頁面上顯示一個 “克隆Range對象” 按鈕,用戶單擊該按鈕時,創建一個Range對象,該對象包含頁面中的所有內容,然後使用cloneRange方法複製Range對象,然後在彈窗顯示該Range對象中的內容。
代碼如下:
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
cloneContents: 該方法用於在頁面上追加一段HTML代碼,使用方法如下:
var docFragment = rangeObj.cloneContents();
該方法返回的是 一個 DocumentFragment對象,該對象爲一個容器元素,當需要追加,修改,刪除或查找頁面上的元素時,該方法非常有用。
下面是一個demo,頁面上顯示一個div元素,div元素中包含一些文字和一個按鈕,用戶點擊按鈕時將在該div元素底部克隆出相同的文字和按鈕。
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
extraContents: 該方法用於將Range對象所代表區域的HTML代碼克隆到一個 DocumentFragment中,然後從頁面中刪除這段HTML代碼;
使用方法如下:
var documentFragment = rangeObj.extraContents();
下面是一個demo, 頁面上有2個div元素和一個按鈕,其中第一個div元素包含一些文字,用戶單擊該按鈕時,把文字移動到第二個div中。
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
2-4 insertNode方法
該方法用於將指定的節點插入到某個Range對象所代表的區域中,插入位置爲Range對象所代表區域的起點位置,如果該節點已經存在於頁面之中,那麼該節點
將被移動到Range對象所代表區域的起點處。
使用方法如下:
rangeObj.insertNode(node)
下面是一個demo,頁面中有一個div元素和一個按鈕,div元素有一些文字,在div元素中按下鼠標左鍵時,該按鈕將被移動到按下鼠標左鍵的位置。
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
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內容,將顯示空字符串。
代碼如下:
[](javascript:void(0)😉
<!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>
[](javascript:void(0)😉
detach方法: 該方法用於從瀏覽器中釋放Range對象,釋放之後將不能再訪問該Range對象,否則將拋出腳本錯誤,使用方法如下:
RangeObj.detach();