JavaScript高級(jí)程序設(shè)計(jì)(第三版) 第11 章 DOM 擴(kuò)展 和 第12章

1### Menu

第11 章 DOM 擴(kuò)展

11.1.1 querySelector()方法
11.1.2 querySelectorAll()方法
11.1.3 element.matches() element.webkitMatchesSelector()方法
11.2 元素遍歷
HTML5 - 11.3.1 與類(lèi)相關(guān)的擴(kuò)充
HTML5 - 11.3.2 焦點(diǎn)管理
HTML5 - 11.3.3HTMLDocument的變化
HTML5 - 11.3.4 字符集屬性
HTML5 - 11.3.5 自定義數(shù)據(jù)屬性
HTML5 - 11.3.6 插入標(biāo)記
    1. innerHTML 屬性
    1. outerHTML 屬性
    1. insertAdjacentHTML()方法
    1. 內(nèi)存與性能問(wèn)題
11.4 專(zhuān)有擴(kuò)展
  • 11.4.1 文檔模式
  • 11.4.2 children屬性
  • 11.4.3 contains()方法 & compareDocumentPosition()方法
  • 11.4.4 插入文本
    - 1. innerText 屬性
    - 2. outerText 屬性
  • 11.4.5 滾動(dòng)

第12 章 DOM2 和DOM3

12.2 樣式
  • 12.2.1 訪問(wèn)元素的樣式
      1. DOM 樣式屬性和方法
      1. 計(jì)算的樣式
  • 12.2.2 操作樣式表
      1. CSS 規(guī)則
      1. 創(chuàng)建規(guī)則
      1. 刪除規(guī)則
  • 12.2.3 元素大小
      1. 偏移量
      1. 客戶區(qū)大小
      1. 滾動(dòng)大小
      1. 確定元素大小
  • 12.3 遍歷
    • 12.3.1 NodeIterator
    • 12.3.2 TreeWalker
  • 12.4 范圍
    • 12.4.1 DOM中的范圍
        1. 用 DOM 范圍實(shí)現(xiàn)簡(jiǎn)單選擇
        1. 用 DOM 范圍實(shí)現(xiàn)復(fù)雜選擇
        1. 操作 DOM 范圍中的內(nèi)容
        1. 插入 DOM 范圍中的內(nèi)容
        1. 折疊 DOM 范圍
        1. 比較 DOM 范圍
        1. 復(fù)制 DOM 范圍
        1. 清理 DOM 范圍

  • 11.1.1 querySelector()方法
  • querySelector()方法接收一個(gè) CSS 選擇符,返回與該模式匹配的第一個(gè)元素,如果沒(méi)有找到匹配的元素,返回 null。
//取得 body 元素
var body = document.querySelector("body");
//取得 ID 為"myDiv"的元素
var myDiv = document.querySelector("#myDiv");
//取得類(lèi)為"selected"的第一個(gè)元素
var selected = document.querySelector(".selected");
//取得類(lèi)為"button"的第一個(gè)圖像元素
var img = document.body.querySelector("img.button");
  • 通過(guò) Document 類(lèi)型調(diào)用 querySelector()方法時(shí),會(huì)在文檔元素的范圍內(nèi)查找匹配的元素。而通過(guò) Element 類(lèi)型調(diào)用 querySelector()方法時(shí),只會(huì)在該元素后代元素的范圍內(nèi)查找匹配的元素。
  • CSS 選擇符可以簡(jiǎn)單也可以復(fù)雜,視情況而定。如果傳入了不被支持的選擇符, querySelector()會(huì)拋出錯(cuò)誤。

  • 11.1.2 querySelectorAll()方法
  • querySelectorAll() 方法接收的參數(shù)與 querySelector()方法一樣,都是一個(gè) CSS 選擇符,返回的是一個(gè) NodeList 的實(shí)例。
  • 只要傳給 querySelectorAll()方法的 CSS 選擇符有效,該方法都會(huì)返回一個(gè) NodeList 對(duì)象,而不管找到多少匹配的元素。如果沒(méi)有找到匹配的元素, NodeList 就是空的。
  • 與 querySelector()類(lèi)似,能夠調(diào)用 querySelectorAll()方法的類(lèi)型包括 Document、DocumentFragment 和 Element。
//取得某<div>中的所有<em>元素(類(lèi)似于 getElementsByTagName("em"))
var ems = document.getElementById("myDiv").querySelectorAll("em");
//取得類(lèi)為"selected"的所有元素
var selecteds = document.querySelectorAll(".selected");
//取得所有<p>元素中的所有<strong>元素
var strongs = document.querySelectorAll("p strong");
  • 要取得返回的 NodeList 中的每一個(gè)元素,可以使用 item()方法,也可以使用方括號(hào)語(yǔ)法
var i, len, strong;
for (i=0, len=strongs.length; i < len; i++){
strong = strongs[i]; //或者 strongs.item(i)
strong.className = "important";
}

11.1.3 element.matches() element.webkitMatchesSelector()方法
  • 這個(gè)方法接收一個(gè)參數(shù),即 CSS 選擇符,如果調(diào)用元素與該選擇符匹配,返回 true;否則,返回 false。
  • 在取得某個(gè)元素引用的情況下,使用這個(gè)方法能夠方便地檢測(cè)它是否會(huì)被 querySelector() 或 querySelectorAll()方法返回。
  • webkitMatchesSelector() // 除了IE其它瀏覽器用這個(gè)方法match
  • msMatchesSelector():IE瀏覽器用這個(gè)方法
if (document.body.webkitMatchesSelector("body.page1")){
  //true
}

  • 11.2 元素遍歷
  • 在使用 childNodes時(shí)會(huì)返回除了元素節(jié)點(diǎn)以外的所有節(jié)點(diǎn),為了彌補(bǔ)這一差異,而同時(shí)又保持 DOM 規(guī)范不變, Element Traversal 規(guī)范(www.w3.org/TR/ElementTraversal/)新定義了一組屬性。
  • Element Traversal API 為 DOM 元素添加了以下 5 個(gè)屬性。
  • childElementCount:返回子元素(不包括文本節(jié)點(diǎn)和注釋?zhuān)┑膫€(gè)數(shù)。
  • firstElementChild:指向第一個(gè)子元素; firstChild 的元素版。
  • lastElementChild:指向最后一個(gè)子元素; lastChild 的元素版。
  • previousElementSibling:指向前一個(gè)同輩元素; previousSibling 的元素版。
  • nextElementSibling:指向后一個(gè)同輩元素; nextSibling 的元素版。
    支持的瀏覽器為 DOM 元素添加了這些屬性,利用這些元素不必?fù)?dān)心空白文本節(jié)點(diǎn)

  • HTML5 - 11.3.1 與類(lèi)相關(guān)的擴(kuò)充
  • 1. getElementsByClassName()方法
  • 可以通過(guò) document對(duì)象及所有 HTML 元素調(diào)用該方法;
  • getElementsByClassName()方法接收一個(gè)參數(shù),該參數(shù)可以是一個(gè)或多個(gè)類(lèi)名字符串,通過(guò)空格分隔;
  • 該方法會(huì)返回element或document的后代元素中匹配的元素,返回的是NodeList動(dòng)態(tài)集合類(lèi)型;
//取得所有類(lèi)中包含"username"和"current"的元素,類(lèi)名的先后順序無(wú)所謂
var allCurrentUsernames = document.getElementsByClassName("username current");
//取得 ID 為"myDiv"的元素中帶有類(lèi)名"selected"的所有元素
var selected = document.getElementById("myDiv").getElementsByClassName("selected");
  • 2. classList 屬性
  • 通過(guò) className 屬性為element添加、刪除和替換類(lèi)名。
  • 這個(gè) classList 屬性是新集合類(lèi)型 DOMTokenList 的實(shí)例。與其他 DOM 集合類(lèi)似;
  • DOMTokenList 有一個(gè)表示自己包含多少元素的 length 屬性,而要取得每個(gè)元素可以使用 item()方法,也可以使用方括號(hào)語(yǔ)法。此外,這個(gè)新類(lèi)型還定義如下方法。
  • add(value):將給定的字符串值添加到列表中。如果值已經(jīng)存在,就不添加了。
  • contains(value):表示列表中是否存在給定的值,如果存在則返回 true,否則返回 false。
  • remove(value):從列表中刪除給定的字符串。
  • toggle(value):如果列表中已經(jīng)存在給定的值,刪除它;如果列表中沒(méi)有給定的值,添加它。
//刪除"disabled"類(lèi)
div.classList.remove("disabled");
//添加"current"類(lèi)
div.classList.add("current");
//切換"user"類(lèi)
div.classList.toggle("user");
//確定元素中是否包含既定的類(lèi)名
if (div.classList.contains("bd") && !div.classList.contains("disabled")){
//執(zhí)行操作
)
//迭代類(lèi)名
for (var i=0, len=div.classList.length; i < len; i++){
doSomething(div.classList[i]);
}

HTML5 - 11.3.2 焦點(diǎn)管理
  • document.activeElement 屬性,這個(gè)屬性始終會(huì)引用 DOM 中當(dāng)前獲得了焦點(diǎn)的元素。
  • 元素獲得焦點(diǎn)的方式有頁(yè)面加載、用戶輸入(通常是通過(guò)按 Tab 鍵)和在代碼中調(diào)用 focus()方法。
var button = document.getElementById("myButton");
button.focus();
alert(document.activeElement === button); //true
  • document.hasFocus()方法,這個(gè)方法用于確定文檔是否獲得了焦點(diǎn)。
var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus());   //true

11.3.3 HTML5 - HTMLDocument的變化
  • 1. readyState 屬性
  • Document 的 readyState 屬性有兩個(gè)可能的值:
    • loading,正在加載文檔;
    • complete,已經(jīng)加載完文檔。
if (document.readyState == "complete"){
//執(zhí)行操作
}
  • 2. 兼容模式

  • 檢測(cè)頁(yè)面的兼容模式 document.compatMode ;

  • 在標(biāo)準(zhǔn)模式下, document.compatMode 的值等于"CSS1Compat",

  • 而在混雜模式下, document.compatMode 的值等于"BackCompat"

  • 3. head 屬性

  • document.head 屬性,引用文檔的<head>元素。


HTML5 - 11.3.4 字符集屬性
  • charset
  • charset屬性表示文檔中實(shí)際使用的字符集,也可以用來(lái)指定新字符集。
  • 默認(rèn)情況下,這個(gè)屬性的值為"UTF-16",但可以通過(guò)<meta>元素、響應(yīng)頭
    部或直接設(shè)置 charset 屬性修改這個(gè)值。來(lái)看一個(gè)例子。
alert(document.charset); //"UTF-16"
document.charset = "UTF-8";
  • defaultCharset
  • 另一個(gè)屬性是 defaultCharset,表示根據(jù)默認(rèn)瀏覽器及操作系統(tǒng)的設(shè)置,當(dāng)前文檔默認(rèn)的字符集應(yīng)該是什么。如果文檔沒(méi)有使用默認(rèn)的字符集,那 charset 和 defaultCharset 屬性的值可能會(huì)不一樣;

HTML5 - 11.3.5 自定義數(shù)據(jù)屬性
  • HTML5 規(guī)定可以為元素添加非標(biāo)準(zhǔn)的屬性,但要添加前綴 data-,目的是為元素提供與渲染無(wú)關(guān)的信息,或者提供語(yǔ)義信息。這些屬性可以任意添加、隨便命名,只要以 data-開(kāi)頭即可。
<div id="myDiv" data-appId="12345" data-myname="Nicholas"></div>
  • 添加了自定義屬性之后,可以通過(guò)元素的 dataset 屬性來(lái)訪問(wèn)自定義屬性的值。 dataset 屬性的值是 DOMStringMap 的一個(gè)實(shí)例,也就是一個(gè)名值對(duì)兒的映射。
var div = document.getElementById("myDiv");
//取得自定義屬性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//設(shè)置值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";

HTML5 - 11.3.6 插入標(biāo)記
  • 1. innerHTML 屬性
  • 在讀模式下, innerHTML 屬性返回與調(diào)用元素的所有子節(jié)點(diǎn)(包括元素、注釋和文本節(jié)點(diǎn))對(duì)應(yīng)的 HTML 標(biāo)記。
  • 在寫(xiě)模式下, innerHTML 會(huì)根據(jù)指定的值創(chuàng)建新的 DOM 樹(shù),然后用這個(gè) DOM 樹(shù)完全替換調(diào)用元素原先的所有子節(jié)點(diǎn)。
  • 在子節(jié)點(diǎn)的內(nèi)容被替換后,被替換的元素節(jié)點(diǎn)的屬性,事件處理等還會(huì)留在屬性里,所以需要先刪除屬性和的事件,在做替換;
div = document.createElement("div");
div.innerHTML = "outside left <b>bold font...</b> out right";
document.body.appendChild(div)
  • 并不是所有元素都支持 innerHTML 屬性。不支持 innerHTML 的元素有: <col>、 <colgroup>、<frameset>、 <head>、 <html>、 <style>、 <table>、 <tbody>、 <thead>、 <tfoot>和<tr>。

  • 2. outerHTML 屬性
  • 在讀模式下, outerHTML 返回調(diào)用它的元素及所有子節(jié)點(diǎn)的 HTML 標(biāo)簽。在寫(xiě)模式下, outerHTML會(huì)根據(jù)指定的 HTML 字符串創(chuàng)建新的 DOM 子樹(shù),然后用這個(gè) DOM 子樹(shù)完全替換調(diào)用元素。
  • 在子節(jié)點(diǎn)的內(nèi)容被替換后,被替換的元素節(jié)點(diǎn)的屬性,事件處理等還會(huì)留在屬性里,所以需要先刪除屬性和的事件,在做替換;
<div id="content">
    <p>in div paragraph..</p>
</div>
<script>
div = document.getElementById("content");
div.outerHTML = "<p>It's replace content <strong>paragraph111</strong></p>";
// It's replace content paragraph111
</script>
div元素被替換掉了

  • 3. insertAdjacentHTML()方法

  • 插入標(biāo)記的最后一個(gè)新增方式是 insertAdjacentHTML()方法。這個(gè)方法最早也是在 IE中出現(xiàn)的,它接收兩個(gè)參數(shù):插入位置和要插入的 HTML 文本。第一個(gè)參數(shù)必須是下列值之一:

    • "beforebegin",在當(dāng)前元素之前插入一個(gè)緊鄰的同輩元素;
    • "afterbegin",在當(dāng)前元素之下插入一個(gè)新的子元素或在第一個(gè)子元素之前再插入新的子元素;
    • "beforeend",在當(dāng)前元素之下插入一個(gè)新的子元素或在最后一個(gè)子元素之后再插入新的子元素;
    • "afterend",在當(dāng)前元素之后插入一個(gè)緊鄰的同輩元素
//作為前一個(gè)同輩元素插入
element.insertAdjacentHTML("beforebegin", "<p>Hello world!</p>");
//作為第一個(gè)子元素插入
element.insertAdjacentHTML("afterbegin", "<p>Hello world!</p>");
//作為最后一個(gè)子元素插入
element.insertAdjacentHTML("beforeend", "<p>Hello world!</p>");
//作為后一個(gè)同輩元素插入
element.insertAdjacentHTML("afterend", "<p>Hello world!</p>");

  • 4. 內(nèi)存與性能問(wèn)題
    • 在子節(jié)點(diǎn)的內(nèi)容被替換后,被替換的元素節(jié)點(diǎn)的屬性,事件處理等還會(huì)留在屬性里,所以需要先刪除屬性和的事件,在做替換;
    • 如果在一個(gè)循環(huán)體里多次調(diào)用innerHTML、outerHtml會(huì)影響性能,最好把return的內(nèi)容先賦給一個(gè)變量,讓后在調(diào)用innerHTML。

11.4 專(zhuān)有擴(kuò)展
  • 11.4.1 文檔模式
  • doctype 最好使用標(biāo)準(zhǔn)模式 <!DOCTYPE html>

  • 11.4.2 children屬性
  • children屬性是 HTMLCollection 的實(shí)例,和childNodes一樣返回子節(jié)點(diǎn),但是不返回textNode等其他節(jié)點(diǎn),只返回子元素節(jié)點(diǎn);

  • 11.4.3 contains()方法 & compareDocumentPosition()方法
  • 返回元素節(jié)點(diǎn)是否被包含;
  • alert(htmlNode.contains(bodyNode)); // true
  • 返回alert(bodyNode.contains(htmlNode)); // false

compareDocumentPosition()方法

  • 后面的給定元素的相對(duì)參考元素(前面的調(diào)用元素)位置,并返回位置掩碼;
    <div id="mydiv">
        <ul>
            <p id="myp"><span id="myspan">spanaaa</span></p>
            <li>line 1</li>
            <li>line 2</li>
            <li>line 3</li>
        </ul>
    </div>
    <script>
        mydiv = document.getElementById("mydiv");
        myspan = document.getElementById("myspan");
        // 包含8 + 居前2 = 10
        document.write(myspan.compareDocumentPosition(mydiv))
        // 被包含16 + 居后4 = 20
        document.write(mydiv.compareDocumentPosition(myspan))
    </script>

  • 11.4.4 插入文本
      1. innerText 屬性
      • 設(shè)置 innerText 永遠(yuǎn)只會(huì)生成當(dāng)前節(jié)點(diǎn)的一個(gè)子文本節(jié)點(diǎn),而為了確保只生成一個(gè)子文本節(jié)點(diǎn),
        就必須要對(duì)文本進(jìn)行 HTML 編碼。利用這一點(diǎn),可以通過(guò) innerText 屬性過(guò)濾掉 HTML 標(biāo)簽。方法是
        將 innerText 設(shè)置為等于 innerText,這樣就可以去掉所有 HTML 標(biāo)簽,比如:
        div.innerText = div.innerText;
      1. outerText 屬性
      • 與innerText 屬性作用相同,只是替換會(huì)替換整個(gè)元素;

第12 章 DOM2 和DOM3

  • OM1 級(jí)主要定義的是 HTML 和 XML 文檔的底層結(jié)構(gòu)。 DOM2 和 DOM3 級(jí)則在這個(gè)結(jié)構(gòu)
    的基礎(chǔ)上引入了更多的交互能力,也支持了更高級(jí)的 XML 特性。為此, DOM2 和 DOM3
    級(jí)分為許多模塊(模塊之間具有某種關(guān)聯(lián)),分別描述了 DOM 的某個(gè)非常具體的子集。這些模塊
    如下。
  • DOM2 級(jí)核心(DOM Level 2 Core):在 1 級(jí)核心基礎(chǔ)上構(gòu)建,為節(jié)點(diǎn)添加了更多方法和屬性。
  • DOM2 級(jí)視圖(DOM Level 2 Views):為文檔定義了基于樣式信息的不同視圖。
  • DOM2 級(jí)事件(DOM Level 2 Events):說(shuō)明了如何使用事件與 DOM 文檔交互。
  • DOM2 級(jí)樣式(DOM Level 2 Style):定義了如何以編程方式來(lái)訪問(wèn)和改變 CSS 樣式信息。
  • DOM2 級(jí)遍歷和范圍(DOM Level 2 Traversal and Range):引入了遍歷 DOM 文檔和選擇其特定
    部分的新接口。
  • DOM2 級(jí) HTML(DOM Level 2 HTML):在 1 級(jí) HTML 基礎(chǔ)上構(gòu)建,添加了更多屬性、方法和
    新接口。
DOM 變化
  • 可以通過(guò)下列代碼來(lái)確定瀏覽器是否支持這些 DOM 模塊;
var supportsDOM2Core = document.implementation.hasFeature("Core", "2.0");
var supportsDOM3Core = document.implementation.hasFeature("Core", "3.0");
var supportsDOM2HTML = document.implementation.hasFeature("HTML", "2.0");
var supportsDOM2Views = document.implementation.hasFeature("Views", "2.0");
var supportsDOM2XML = document.implementation.hasFeature("XML", "2.0");

12.2 樣式
  • 確定瀏覽器是否支持 DOM3 級(jí)定義的 CSS3 能力
alert(document.implementation.hasFeature("CSS3.0", "3.0"));  // true
  • 12.2.1 訪問(wèn)元素的樣式
  • 通過(guò)元素的style屬性來(lái)操作樣式;
//設(shè)置背景顏色
myDiv.style.backgroundColor = "red";
  • 對(duì)于使用短劃線(分隔不同的詞匯,例如 background-image)的 CSS 屬性名,必須將其轉(zhuǎn)換成駝峰大小寫(xiě)形式,才能通過(guò) JavaScript 來(lái)訪問(wèn);例如:()background-image > style.backgroundImage)
  • 在標(biāo)準(zhǔn)模式下,所有度量值都必須指定一個(gè)度量單位。
myDiv.style.width = "100px";
myDiv.style.height = "200px";

  • 1. DOM 樣式屬性和方法
    // cssText:get or set element of style;
    mydiv.style.cssText = "width: 25px; height: 100px; background-color: green";
    alert(mydiv.style.cssText);

    // parentRule: The following JavaScript code gets the parent CSS style rule from a CSSStyleDeclaration:
    var declaration = document.styleSheets[0].cssRules[0].style;
    var rule = declaration.parentRule;

    // getPropertyPriority :檢查rule的給定的property是否設(shè)置了!important,如果是就返回"important"
    var declaration1 = document.styleSheets[0].cssRules[0].style;
    var isImportant = declaration1.getPropertyPriority('margin') === 'important';

    // style.getPropertyValue: 返回css屬性的值
    // The following JavaScript code queries the value of the margin property in a CSS selector rule:
    var declaration2 = document.styleSheets[0].cssRules[0].style;
    var value = declaration2.getPropertyValue('margin'); // "1px 2px"

    // style.removeProperty: 刪除css屬性
    var declaration3 = document.styleSheets[0].cssRules[0].style;
    var oldValue = declaration3.removeProperty('background-color');
    
    // style.setProperty: 添加css屬性
    var declaration = document.styleSheets[0].cssRules[0].style;
    declaration.setProperty('border-width', '1px 2px');
    // Equivalent to:
    // declaration.borderWidth = '1px 2px';

2. 計(jì)算的樣式

  • document.defaultView.getComputedStyle(element, null)
  • 所有計(jì)算的樣式都是只讀的;不能修改計(jì)算后樣式對(duì)象中的 CSS 屬性。此外,計(jì)算后的樣式也包含屬于瀏覽器內(nèi)部樣式表的樣式信息,因此任何具有默認(rèn)值的 CSS 屬性都會(huì)表現(xiàn)在計(jì)算后的樣式中。
  • 返回一個(gè)CSSStyleDeclaration 對(duì)象(與 style 屬性的類(lèi)型相同),其中包含當(dāng)前元素的所有計(jì)算的樣式,可以通過(guò)這個(gè)對(duì)象get到element計(jì)算后的最終樣式;
    <style>
        #myp {
            border:1px solid red;
            color: #ff00d8;
            font-size:30px;
        }
        #mydiv {
            background-color: pink;
        }
    </style>
</head>
<body>
<div id="mydiv">
    <p id="myp" style="color:purple;font-size:30px;background-color: dodgerblue;">in div paragraph..</p>
</div>
<script>
    function notinarray(obj, arr) {
        var i = arr.length;
        while (i--) {
            if (arr[i] === obj) {
                return false;
            }
        }
        return true;
    }
    myp = document.getElementById("myp");
    // return CSSStyleDeclaration對(duì)象 of this element
    computedStyle = window.getComputedStyle(myp, null);  
    //  // 找到跟element對(duì)應(yīng)的那條規(guī)則的cssText; cssRulesText = 內(nèi)嵌cssRule + inline cssRule
    var cssRulesText = (document.styleSheets[0].cssRules[0].style.cssText) + " " + myp.style.cssText; 
    // 正則得到css屬性名;
    var patt=new RegExp(/([a-z-]+):/g);
    
    // css屬性去重;
    dictre = [];
    while (true){
        var re = patt.exec(cssRulesText);
        if (re==null){break}
        if (notinarray(re[1], dictre)){
            dictre.push(re[1])
        }
    }
    // 打印this element的 css屬性computed值
    for (let i=0, len=dictre.length; i<len; i++){
        let attr = dictre[i];
        document.write(attr, "  : ", computedStyle[attr], "<br> ")
    }

    // border : 1px solid rgb(255, 0, 0)   // 只有chrome會(huì)顯示border屬性的值
    // color : rgb(128, 0, 128)
    // font-size : 30px
    // background-color : rgb(30, 144, 255)

  • 12.2.2 操作樣式表

  • CSSStyleSheet 繼承自 StyleSheet,后者可以作為一個(gè)基礎(chǔ)接口來(lái)定義非 CSS 樣式表。從StyleSheet 接口繼承而來(lái)的屬性如下。

    • disabled:表示樣式表是否被禁用的布爾值。這個(gè)屬性是可讀/寫(xiě)的,將這個(gè)值設(shè)置為 true 可以禁用樣式表。
    • href:如果樣式表是通過(guò)<link>包含的,則是樣式表的 URL;否則,是 null。
    • media:當(dāng)前樣式表支持的所有媒體類(lèi)型的集合。與所有 DOM 集合一樣,這個(gè)集合也有一個(gè)length 屬性和一個(gè) item()方法。也可以使用方括號(hào)語(yǔ)法取得集合中特定的項(xiàng)。如果集合是空列表,表示樣式表適用于所有媒體。在 IE 中, media 是一個(gè)反映<link>和<style>元素 media特性值的字符串。
    • ownerNode:指向擁有當(dāng)前樣式表的節(jié)點(diǎn)的指針,樣式表可能是在 HTML 中通過(guò)<link>或<style/>引入的(在 XML 中可能是通過(guò)處理指令引入的)。如果當(dāng)前樣式表是其他樣式表通過(guò)@import 導(dǎo)入的,則這個(gè)屬性值為 null。 IE 不支持這個(gè)屬性。
    • parentStyleSheet:在當(dāng)前樣式表是通過(guò)@import 導(dǎo)入的情況下,這個(gè)屬性是一個(gè)指向?qū)胨臉邮奖淼闹羔槨?/li>
    • title: ownerNode 中 title 屬性的值。
    • type:表示樣式表類(lèi)型的字符串。對(duì) CSS 樣式表而言,這個(gè)字符串是"type/css"。除 了 disabled 屬 性 之 外 , 其 他 屬 性 都 是 只 讀 的 。 在 支 持 以 上 所 有 這 些 屬 性 的 基 礎(chǔ) 上 ,CSSStyleSheet 類(lèi)型還支持下列屬性和方法:
      • cssRules:樣式表中包含的樣式規(guī)則的集合。 IE 不支持這個(gè)屬性,但有一個(gè)類(lèi)似的 rules 屬性。
      • ownerRule:如果樣式表是通過(guò)@import 導(dǎo)入的,這個(gè)屬性就是一個(gè)指針,指向表示導(dǎo)入的規(guī)則;否則,值為 null。 IE 不支持這個(gè)屬性。
      • deleteRule(index):刪除 cssRules 集合中指定位置的規(guī)則。 IE 不支持這個(gè)方法,但支持一個(gè)類(lèi)似的 removeRule()方法。
      • insertRule(rule,index):向 cssRules 集合中指定的位置插入 rule 字符串。 IE 不支持這
        個(gè)方法,但支持一個(gè)類(lèi)似的 addRule()方法。
    • 應(yīng)用于文檔的所有樣式表是通過(guò) document.styleSheets 集合來(lái)表示的。通過(guò)這個(gè)集合的 length屬性可以獲知文檔中樣式表的數(shù)量,而通過(guò)方括號(hào)語(yǔ)法或 item()方法可以訪問(wèn)每一個(gè)樣式表。
  • 也可以直接通過(guò)<link>或<style>元素取得 CSSStyleSheet 對(duì)象。 DOM 規(guī)定了一個(gè)包含CSSStyleSheet 對(duì)象的屬性,名叫 sheet;除了 IE,其他瀏覽器都支持這個(gè)屬性。 IE 支持的是styleSheet 屬性。要想在不同瀏覽器中都能取得樣式表對(duì)象,可以使用下列代碼。

function getStyleSheet(element){
return element.sheet || element.styleSheet;
}
//取得第一個(gè)<link/>元素引入的樣式表
var link = document.getElementsByTagName("link")[0];
// 這里的 getStyleSheet()返回的樣式表對(duì)象與 document.styleSheets 集合中的樣式表對(duì)象相同。
var sheet = getStylesheet(link);  

1. CSS 規(guī)則
CSSRule 對(duì)象表示樣式表中的每一條規(guī)則。實(shí)際上, CSSRule 是一個(gè)供其他多種類(lèi)型繼承的基類(lèi)型,其中最常見(jiàn)的就是 CSSStyleRule 類(lèi)型,表示樣式信息(其他規(guī)則還有@import、 @font-face、@page 和@charset,但這些規(guī)則很少有必要通過(guò)腳本來(lái)訪問(wèn))。 CSSStyleRule 對(duì)象包含下列屬性。
- cssText:返回整條規(guī)則對(duì)應(yīng)的文本。由于瀏覽器對(duì)樣式表的內(nèi)部處理方式不同,返回的文本可能會(huì)與樣式表中實(shí)際的文本不一樣; Safari 始終都會(huì)將文本轉(zhuǎn)換成全部小寫(xiě)。 IE 不支持這個(gè)屬性。
- parentRule:如果當(dāng)前規(guī)則是導(dǎo)入的規(guī)則,這個(gè)屬性引用的就是導(dǎo)入規(guī)則;否則,這個(gè)值為null。 IE 不支持這個(gè)屬性。
- parentStyleSheet:當(dāng)前規(guī)則所屬的樣式表。 IE 不支持這個(gè)屬性。
- selectorText:返回當(dāng)前規(guī)則的選擇符文本。由于瀏覽器對(duì)樣式表的內(nèi)部處理方式不同,返回的文本可能會(huì)與樣式表中實(shí)際的文本不一樣(例如, Safari 3 之前的版本始終會(huì)將文本轉(zhuǎn)換成全部小寫(xiě)) 。在 Firefox、 Safari、 Chrome 和 IE 中這個(gè)屬性是只讀的。 Opera 允許修改 selectorText。
- style:一個(gè) CSSStyleDeclaration 對(duì)象,可以通過(guò)它設(shè)置和取得規(guī)則中特定的樣式值。
- type:表示規(guī)則類(lèi)型的常量值。對(duì)于樣式規(guī)則,這個(gè)值是 1。 IE 不支持這個(gè)屬性。

  • 其中三個(gè)最常用的屬性是 cssText、 selectorText 和 style。 cssText 屬性與 style.cssText屬性類(lèi)似,但并不相同。前者包含選擇符文本和圍繞樣式信息的花括號(hào),后者只包含樣式信息(類(lèi)似于元素的 style.cssText)。此外, cssText 是只讀的,而 style.cssText 也可以被重寫(xiě)。

  • 大多數(shù)情況下,僅使用 style 屬性就可以滿足所有操作樣式規(guī)則的需求了。這個(gè)對(duì)象就像每個(gè)元素上的 style 屬性一樣,可以通過(guò)它讀取和修改規(guī)則中的樣式信息。

// 假設(shè)這條規(guī)則位于頁(yè)面中的第一個(gè)樣式表中,而且這個(gè)樣式表中只有這一條樣式規(guī)則
div.box {
background-color: blue;
width: 100px;
height: 200px;
}

var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得規(guī)則列表
var rule = rules[0]; //取得第一條規(guī)則
alert(rule.selectorText); //"div.box"
alert(rule.style.cssText); //完整的 CSS 代碼
alert(rule.style.backgroundColor); //"blue"
alert(rule.style.width); //"100px"
alert(rule.style.height); //"200px"
  • 使用這種方式,可以像確定元素的行內(nèi)樣式信息一樣,確定與規(guī)則相關(guān)的樣式信息。與使用元素的方式一樣,在這種方式下也可以修改樣式信息。
var sheet = document.styleSheets[0];
var rules = sheet.cssRules || sheet.rules; //取得規(guī)則列表
var rule = rules[0]; //取得第一條規(guī)則
rule.style.backgroundColor = "red"
//以這種方式修改規(guī)則會(huì)影響頁(yè)面中適用于該規(guī)則的所有元素。
//如果有兩個(gè)帶有 box 類(lèi)的<div>元素, 這兩個(gè)元素都會(huì)應(yīng)用修改后的樣式。

2. 創(chuàng)建規(guī)則

function insertRule(sheet, selectorText, cssText, position){
    if (sheet.insertRule){
        sheet.insertRule(selectorText + "{" + cssText + "}", position);
    } else if (sheet.addRule){
        sheet.addRule(selectorText, cssText, position);
    }
}
//下面是調(diào)用這個(gè)函數(shù)的示例代碼。
insertRule(document.styleSheets[0], "body", "background-color: silver", 0);

3. 刪除規(guī)則

var sheet = document.styleSheets[0];
function deleteRule(sheet, index){
    if (sheet.deleteRule){                 // 除IE以外的瀏覽器的方法
        sheet.deleteRule(index);
    } else if (sheet.removeRule){      // IE瀏覽器的方法
        sheet.removeRule(index);
    }
}

- 12.2.3 元素大小
1. 偏移量

  • 包括元素在屏幕上占用的所有可見(jiàn)的空間。
  • offsetHeight:元素在垂直方向上占用的空間大小,以像素計(jì)。包括元素的高度、(可見(jiàn)的)水平滾動(dòng)條的高度、上邊框高度和下邊框高度。
  • offsetWidth:元素在水平方向上占用的空間大小,以像素計(jì)。包括元素的寬度、(可見(jiàn)的)垂直滾動(dòng)條的寬度、左邊框?qū)挾群陀疫吙驅(qū)挾取?/li>
  • offsetLeft:元素的左外邊框至包含元素的左內(nèi)邊框之間的像素距離。
  • offsetTop:元素的上外邊框至包含元素的上內(nèi)邊框之間的像素距離。
  • offsetLeft 和 offsetTop 屬性與包含元素有關(guān),包含元素的引用保存在 offsetParent屬性中。
  • 要想知道某個(gè)元素在頁(yè)面上的偏移量,將這個(gè)元素的 offsetLeft 和 offsetTop 與其 offsetParent的相同屬性相加,如此循環(huán)直至根元素,就可以得到一個(gè)基本準(zhǔn)確的值。
// 以下獲取x軸上的偏移量
    function getElementLeft(element){
        var actualLeft = element.offsetLeft;
        var current = element.offsetParent;
        while (current !== null){
            actualLeft += current.offsetLeft;
            current = current.offsetParent;
        }
        return actualLeft;
    }
// 以下獲取y軸上的偏移量
    function getElementTop(element){
        var actualTop = element.offsetTop;
        var current = element.offsetParent;
        while (current !== null){
            actualTop += current. offsetTop;
            current = current.offsetParent;
        }
        return actualTop;
    }
  • 這兩個(gè)函數(shù)利用 offsetParent 屬性在 DOM 層次中逐級(jí)向上回溯,將每個(gè)層次中的偏移量屬性合計(jì)到一塊。
  • 對(duì)于簡(jiǎn)單的 CSS 布局的頁(yè)面,這兩函數(shù)可以得到非常精確的結(jié)果。對(duì)于使用表格和內(nèi)嵌框架布局的頁(yè)面,由于不同瀏覽器實(shí)現(xiàn)這些元素的方式不同,因此得到的值就不太精確了。


    圖片.png

2. 客戶區(qū)大小

  • 元素內(nèi)容及其內(nèi)邊距所占據(jù)的空間大??;

  • clientWidth

    • 元素內(nèi)容區(qū)寬度加上左右內(nèi)邊距寬度;
  • clientHeight

    • 屬性是元素內(nèi)容區(qū)高度加上上下內(nèi)邊距高度;


      客戶區(qū)大小
  • 客戶區(qū)大小就是元素內(nèi)部的空間大小,因此滾動(dòng)條占用的空間不計(jì)算在內(nèi)。

  • 最常用到這些屬性的情況,就是確定瀏覽器視口大小的時(shí)候。

    function getViewport(){
        if (document.compatMode == "BackCompat"){     //混雜模式用這個(gè)
            return {
                width: document.body.clientWidth,
                height: document.body.clientHeight
            };
        } else {
            return {
                width: document.documentElement.clientWidth,   //標(biāo)準(zhǔn)模式用這個(gè)
                height: document.documentElement.clientHeight
            };
        }
    }
//這個(gè)函數(shù)會(huì)返回一個(gè)對(duì)象,包含兩個(gè)屬性: width和 height;
//表示瀏覽器視口(<html>或<body>元素)的大小。

3. 滾動(dòng)大小

  • scrollHeight:在沒(méi)有滾動(dòng)條的情況下,元素內(nèi)容的總高度。
  • scrollWidth:在沒(méi)有滾動(dòng)條的情況下,元素內(nèi)容的總寬度。
  • scrollLeft:被隱藏在內(nèi)容區(qū)域左側(cè)的像素?cái)?shù)。通過(guò)設(shè)置這個(gè)屬性可以改變?cè)氐臐L動(dòng)位置。
  • scrollTop:被隱藏在內(nèi)容區(qū)域上方的像素?cái)?shù)。通過(guò)設(shè)置這個(gè)屬性可以改變?cè)氐臐L動(dòng)位置。
  • 帶有垂直滾動(dòng)條的頁(yè)面總高度就是 document.documentElement.scrollHeight;
  • 對(duì)于不包含滾動(dòng)條的頁(yè)面而言,scrollWidth 和 clientWidth相等, scrollHeight 和 clientHeight 相等;


    滾動(dòng)大小
  • 通過(guò) scrollLeft 和 scrollTop 屬性確定元素當(dāng)前滾動(dòng)的狀態(tài)
    • 在元素尚未被滾動(dòng)時(shí),這兩個(gè)屬性的值都等于 0。
    • 如果元素被垂直滾動(dòng)了,那么 scrollTop 的值會(huì)大于 0,且表示元素上方不可見(jiàn)內(nèi)容的像素高度。
    • 如果元素被水平滾動(dòng)了,那么 scrollLeft 的值會(huì)大于 0,且表示元素左側(cè)不可見(jiàn)內(nèi)容的像素寬度。
  • 通過(guò) scrollLeft 和 scrollTop 屬性設(shè)置元素的滾動(dòng)位置。
    • 因此將元素的scrollLeft 和 scrollTop 設(shè)置為 0,就可以重置元素的滾動(dòng)位置。
       //檢測(cè)元素是否位于頂部,如果不是就將其回滾到頂部。
       function scrollToTop(element){
           if (element.scrollTop != 0){
               element.scrollTop = 0;
           }
       }

4. 確定元素大小

  • viewport(視口)
    • 等于瀏覽器窗口,擁有瀏覽器窗口的寬度和高度,<html>元素使用viewport寬度的100%(在未手動(dòng)設(shè)置html元素寬度情況下)。用document.documentElement.clientWidth獲取viewport的寬度。
document.write(div.clientWidth,"<br>")
document.write(div.clientHeight,"<br>")
  • 元素大小
    用element.offsetWidth 和 element.offsetHeight 獲取元素大小,元素大小包括
document.write("element", div.offsetWidth,"<br>")
document.write("element", div.offsetHeight,"<br>")
元素大小 page343
  • 1. 偏移量

  • offsetWidth - 返回元素寬,元素寬包括內(nèi)容區(qū) + 左右內(nèi)邊距 + 左右邊框;

  • offsetHeight - 返回元素高,元素寬包括內(nèi)容區(qū) +上下內(nèi)邊距 + 上下邊框;

  • offsetLeft - 表示該元素的border左外邊緣與已定位的父容器(offsetParent對(duì)象)左padding外邊緣的距離(不包括父元素border);

  • offsetTop - 表示該元素的border上外邊緣與已定位的父容器(offsetParent對(duì)象)上padding外邊緣的距離(不包括父元素border);

  • 2. Client 客戶區(qū)大小

  • clientWidth - 元素內(nèi)容寬+內(nèi)邊距 大小,不包括邊框(IE下實(shí)際包括)、外邊距、滾動(dòng)條部分;

  • clientHeight - 元素內(nèi)容高+內(nèi)邊距 大小,不包括邊框(IE下實(shí)際包括)、外邊距、滾動(dòng)條部分;

  • clientLeft - 返回內(nèi)邊距的邊緣和邊框的外邊緣之間的水平距離,也就是左邊框?qū)挾龋?/p>

  • clientTop - 返回內(nèi)邊距的邊緣和邊框的外邊緣之間的垂直距離,也就是上邊框?qū)挾龋?/p>

  • 3. 滾動(dòng)大小

  • scrollWidth - 是只讀屬性,是元素內(nèi)容寬度(左padding外邊緣 - 右padding外邊緣,不包括滾動(dòng)條),包括溢出而在屏幕上不可見(jiàn)的內(nèi)容。

  • scrollHeight - 是只讀屬性,是元素內(nèi)容高度(上padding外邊緣 - 下padding外邊緣,不包括滾動(dòng)條),包括溢出而在屏幕上不可見(jiàn)的內(nèi)容。

  • scrollLeft - 可以獲取 or 設(shè)置一個(gè)元素的內(nèi)容水平滾動(dòng)的像素?cái)?shù)(左邊被隱藏內(nèi)容的寬度的px值);

  • scrollTop - 可以獲取 or 設(shè)置一個(gè)元素的內(nèi)容垂直滾動(dòng)的像素?cái)?shù)(頂部被隱藏內(nèi)容的高度的px值);

  • 比如元素的scrollHeight是1015,clientHeight是303,那么scrollTop就是712;

  • 4. 確定元素大小

  • 每個(gè)元素都提供了一個(gè) getBoundingClientRect()方法。這個(gè)方法返回會(huì)一個(gè)矩形對(duì)象,包含 6 個(gè)屬性: left、 top、 right 和 bottom。還有width和height。這些屬性給出了元素在頁(yè)面中相對(duì)于視口(瀏覽器的視口就是body元素或者h(yuǎn)tml元素的左上角)的位置。

  • getBoundingClientRect()的width屬性 == offsetWidth的值;

  • getBoundingClientRect()的Height屬性 == offsetHeight的值;

12.3 遍歷
  • 12.3.1 NodeIterator
    • 可以使用 document.createNodeIterator()方
      法創(chuàng)建它的新實(shí)例。接受4個(gè)參數(shù):
      • 1.root:想要作為搜索起點(diǎn)的樹(shù)中的節(jié)點(diǎn)。
      • 2.whatToShow:表示要訪問(wèn)哪些節(jié)點(diǎn)的數(shù)字代碼。
        • NodeFilter.SHOW_ALL:顯示所有類(lèi)型的節(jié)點(diǎn)。
        • NodeFilter.SHOW_ELEMENT:顯示元素節(jié)點(diǎn)。
        • NodeFilter.SHOW_ATTRIBUTE:顯示特性節(jié)點(diǎn)。由于 DOM 結(jié)構(gòu)原因,實(shí)際上不能使用這個(gè)值。
        • NodeFilter.SHOW_TEXT:顯示文本節(jié)點(diǎn)。
        • NodeFilter.SHOW_CDATA_SECTION:顯示 CDATA 節(jié)點(diǎn)。對(duì) HTML 頁(yè)面沒(méi)有用。
        • NodeFilter.SHOW_ENTITY_REFERENCE:顯示實(shí)體引用節(jié)點(diǎn)。對(duì) HTML 頁(yè)面沒(méi)有用。
        • NodeFilter.SHOW_ENTITYE:顯示實(shí)體節(jié)點(diǎn)。對(duì) HTML 頁(yè)面沒(méi)有用。
        • NodeFilter.SHOW_PROCESSING_INSTRUCTION:顯示處理指令節(jié)點(diǎn)。對(duì) HTML 頁(yè)面沒(méi)有用。
        • NodeFilter.SHOW_COMMENT:顯示注釋節(jié)點(diǎn)。
        • NodeFilter.SHOW_DOCUMENT:顯示文檔節(jié)點(diǎn)。
        • NodeFilter.SHOW_DOCUMENT_TYPE:顯示文檔類(lèi)型節(jié)點(diǎn)。
        • NodeFilter.SHOW_DOCUMENT_FRAGMENT:顯示文檔片段節(jié)點(diǎn)。對(duì) HTML 頁(yè)面沒(méi)有用。
        • NodeFilter.SHOW_NOTATION:顯示符號(hào)節(jié)點(diǎn)。對(duì) HTML 頁(yè)面沒(méi)有用。
      • 3.filter:是一個(gè) NodeFilter 對(duì)象,或者一個(gè)表示應(yīng)該接受還是拒絕某種特定節(jié)點(diǎn)的函數(shù)。
        • 每個(gè) NodeFilter 對(duì)象只有一個(gè)方法,即 acceptNode();如果應(yīng)該訪問(wèn)給定的節(jié)點(diǎn),該方法返回 NodeFilter.FILTER_ACCEPT,如果不應(yīng)該訪問(wèn)給定的節(jié)點(diǎn),該方法返回 NodeFilter.FILTER_SKIP。由于 NodeFilter 是一個(gè)抽象的類(lèi)型,因此不能直接創(chuàng)建它的實(shí)例。在必要時(shí),只要?jiǎng)?chuàng)建一個(gè)包含 acceptNode()方法的對(duì)象,然后將這個(gè)對(duì)象傳入createNodeIterator()中即可。
    // 創(chuàng)建一個(gè)只顯示<p>元素的節(jié)點(diǎn)迭代器。
    var filter = {
        acceptNode: function(node){
            return node.tagName.toLowerCase() == "p" ?
                NodeFilter.FILTER_ACCEPT :
                NodeFilter.FILTER_SKIP;
        }
    };
    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
        filter, false);

    // 也可以是一個(gè)與 acceptNode()方法類(lèi)似的函數(shù)
    var filter = function(node){
        return node.tagName.toLowerCase() == "p" ?
            NodeFilter.FILTER_ACCEPT :
            NodeFilter.FILTER_SKIP;
    };
    var iterator = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT,
        filter, false);

  • 4.entityReferenceExpansion:布爾值,表示是否要擴(kuò)展實(shí)體引用。這個(gè)參數(shù)在 HTML 頁(yè)面中沒(méi)有用,因?yàn)槠渲械膶?shí)體引用不能擴(kuò)展。

  • NodeIterator 方法

    • nextNode() - 向前前進(jìn)一步
    • previousNode() - 向后后退一步
   <div id="div1">
       <p><b>Hello</b> world!</p>
       <ul>
           <li>List item 1</li>
           <li>List item 2</li>
           <li>List item 3</li>
       </ul>
   </div>
   // 遍歷<div>元素中的所有元素
<script>
     var div = document.getElementById("div1");
   var iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, null, false);
   var node = iterator.nextNode();
   while (node !== null) {
       alert(node.tagName); //輸出標(biāo)簽名
       node = iterator.nextNode();
   }
   // 只想返回遍歷中遇到的<li>元素, 把下面的過(guò)濾器傳入第三個(gè)參數(shù)即可;
   var filter = function(node){
       return node.tagName.toLowerCase() == "li" ?
           NodeFilter.FILTER_ACCEPT :
           NodeFilter.FILTER_SKIP;
   };

</script>
  • 12.3.2 TreeWalker
    • TreeWalker 是 NodeIterator 的一個(gè)更高級(jí)的版本。除了包括 nextNode()和 previousNode()在內(nèi)的相同的功能之外,這個(gè)類(lèi)型還提供了下列用于在不同方向上遍歷 DOM 結(jié)構(gòu)的方法。
    • 方法
      • parentNode():遍歷到當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn);
      • firstChild():遍歷到當(dāng)前節(jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn);
      • lastChild():遍歷到當(dāng)前節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn);
      • nextSibling():遍歷到當(dāng)前節(jié)點(diǎn)的下一個(gè)同輩節(jié)點(diǎn);
      • previousSibling():遍歷到當(dāng)前節(jié)點(diǎn)的上一個(gè)同輩節(jié)點(diǎn)。
    //可以用 TreeWalker來(lái)代替 NodeIterator
    var div = document.getElementById("div1");
    var filter = function(node){
        return node.tagName.toLowerCase() == "li"?
            NodeFilter.FILTER_ACCEPT :
            NodeFilter.FILTER_SKIP;
    };
    var walker= document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT,
        filter, false);
    var node = iterator.nextNode();
    while (node !== null) {
        alert(node.tagName); //輸出標(biāo)簽名
        node = iterator.nextNode();
    }
  • filter 可以返回的值有所不同。除了 NodeFilter.FILTER_ACCEPT 和 NodeFilter.FILTER_SKIP 之外,還可以使用 NodeFilter.FILTER_REJECT, 會(huì)跳過(guò)相應(yīng)節(jié)點(diǎn)及該節(jié)點(diǎn)的整個(gè)子樹(shù)。例如,將前面例子中的
    NodeFilter.FILTER_SKIP 修改成 NodeFilter.FILTER_REJECT,結(jié)果就是不會(huì)訪問(wèn)任何節(jié)點(diǎn)。這是因?yàn)榈谝粋€(gè)返回的節(jié)點(diǎn)是<div>,它的標(biāo)簽名不是"li",于是就會(huì)返回 NodeFilter.FILTER_REJECT,這意味著遍歷會(huì)跳過(guò)整個(gè)子樹(shù)。在這個(gè)例子中, <div>元素是遍歷的根節(jié)點(diǎn),于是結(jié)果就會(huì)停止遍歷。
  • TreeWalker 真正強(qiáng)大的地方在于能夠在 DOM 結(jié)構(gòu)中沿任何方向移動(dòng)。使用 TreeWalker遍歷 DOM 樹(shù),即使不定義過(guò)濾器,也可以取得所有<li>元素。
    var div = document.getElementById("div1");
    var walker = document.createTreeWalker(div, NodeFilter.SHOW_ELEMENT, null, false);
    walker.firstChild(); //轉(zhuǎn)到<p>
    walker.nextSibling(); //轉(zhuǎn)到<ul>
    var node = walker.firstChild(); //轉(zhuǎn)到第一個(gè)<li>
    while (node !== null) {
        alert(node.tagName);
        node = walker.nextSibling();
    }
  • TreeWalker 類(lèi)型還有一個(gè)屬性:currentNode
    • 表示任何遍歷方法在上一次遍歷中返回的節(jié)點(diǎn)。通過(guò)設(shè)置這個(gè)屬性也可以修改遍歷繼續(xù)進(jìn)行的起點(diǎn)。
    var node = walker.nextNode();
    alert(node === walker.currentNode); //true
    walker.currentNode = document.body; //修改起點(diǎn)
12.4 范圍
  • 12.4.1 DOM中的范圍
    • document.createRange()來(lái)創(chuàng)建 DOM 范圍
    • startContainer:range起始節(jié)點(diǎn)的父節(jié)點(diǎn)(即選區(qū)中第一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn))。
    • startOffset:范圍中選中第一個(gè)節(jié)點(diǎn)在其父節(jié)點(diǎn)的 childNodes 集合中的索引。
    • endContainer:range最終節(jié)點(diǎn)的父節(jié)點(diǎn)(即選區(qū)中最后一個(gè)節(jié)點(diǎn)的父節(jié)點(diǎn))。
    • endOffset:范圍中最后一個(gè)子節(jié)點(diǎn)(終點(diǎn))在其父節(jié)點(diǎn)的 childNodes 集合中的索引。如果selectNode 選擇的只有一個(gè)節(jié)點(diǎn),那么endOffset會(huì)返回startOffset的值+1
    • commonAncestorContainer: startContainer 和 endContainer 共同的祖先節(jié)點(diǎn)在文檔樹(shù)中位置最深的那個(gè)(也就是離startContainer 和 endContainer 最近的共同祖先節(jié)點(diǎn) )。
  • 1. 用 DOM 范圍實(shí)現(xiàn)簡(jiǎn)單選擇
    • selectNode() :選擇整個(gè)節(jié)點(diǎn),包括其子節(jié)點(diǎn);
    • selectNodeContents(): 只選擇節(jié)點(diǎn)的子節(jié)點(diǎn)。
      • <p>p content<b>bold font</b>p content</p>
<!DOCTYPE html>
<html>
    <body>
        <p id="p1"><b>Hello</b> world!</p>
    </body>
</html>
<script>
    var range1 = document.createRange();  // create range ins
    range2 = document.createRange();      
    p1 = document.getElementById("p1");
    range1.selectNode(p1);          // select element p
    range2.selectNodeContents(p1);  // select element p 的content 不包括element p
</script>
  • 其他方法
    • setStartBefore(Node):將范圍的起點(diǎn)設(shè)置在 Node 之前,因此 Node 也就是范圍選區(qū)中的第一個(gè)子節(jié)點(diǎn)。
    • setStartAfter(Node):將范圍的起點(diǎn)設(shè)置在 Node 之后,因此 Node 也就不在范圍之內(nèi)了,其下一個(gè)同輩節(jié)點(diǎn)才是范圍選區(qū)中的第一個(gè)子節(jié)點(diǎn)。
    • setEndBefore(Node):將范圍的終點(diǎn)設(shè)置在 Node 之前,因此 Node 也就不在范圍之內(nèi)了,其上一個(gè)同輩節(jié)點(diǎn)才是范圍選區(qū)中的最后一個(gè)子節(jié)點(diǎn)。
    • setEndAfter(Node):將范圍的終點(diǎn)設(shè)置在 Node 之后,因此 Node 也就是范圍選區(qū)中的最后一個(gè)子節(jié)點(diǎn)。
<div id="mydiv">
    <ol id="myol">
        <li>ol Coffee</li>
        <li>ol Tea</li>
        <li>ol Milk</li>
    </ol>
    <p>a paragraph line...</p>
    <ul id="myul">
        <li>ul Coffee</li>
        <li>ul Tea</li>
        <li>ul Milk</li>
    </ul>
</div>
<script>
    olNode = document.getElementById("myol");
    ulNode = document.getElementById("myul");
    var range1 = document.createRange(); //創(chuàng)建range
    var range2 = document.createRange(); //創(chuàng)建range

    range1.setStartBefore(olNode); // 把range的起點(diǎn)放在olNode前面(olNode是range中的第一個(gè)節(jié)點(diǎn))
    range1.setEndAfter(ulNode); //把range的終點(diǎn)放在ulNode后面 (ulNode是range的最后一個(gè)節(jié)點(diǎn))
    document.write(range1.endOffset, "<br>")  // 6
</script>

  • 2. 用 DOM 范圍實(shí)現(xiàn)復(fù)雜選擇
    • setStart() 方法
      • 根據(jù)參數(shù)選擇range第一個(gè)節(jié)點(diǎn), 參數(shù)一傳入start節(jié)點(diǎn)的父節(jié)點(diǎn)(startContainer), 參數(shù)二傳入start節(jié)點(diǎn)在父節(jié)點(diǎn)中的索引(startOffset)。
    • setEnd() 方法
      • 根據(jù)參數(shù)選擇range最后一個(gè)節(jié)點(diǎn), 參數(shù)一傳入end節(jié)點(diǎn)的父節(jié)點(diǎn)(endContainer), 參數(shù)二傳入end節(jié)點(diǎn)在父節(jié)點(diǎn)中的索引加1(endOffset)。
<body>
ol Coffee ol Tea ol Milk a paragraph line... ul Coffee ul Tea ul Milk
<div id="mydiv">
    <ol id="myol">
        <li>ol Coffee</li>
        <li>ol Tea</li>
        <li>ol Milk</li>
    </ol>
    <p>a paragraph line...</p>
    <ul id="myul">
        <li>ul Coffee</li>
        <li>ul Tea</li>
        <li>ul Milk</li>
    </ul>
</div>
<script>
    // range定在ol到ul
    divNode = document.getElementById("mydiv");
    rangeIns = document.createRange();
    rangeIns.setStart(divNode, 1);
    //用父節(jié)點(diǎn)的childNodes的遍歷確定setEnd節(jié)點(diǎn)的偏移值(跟endOffset一樣是childnodes的length從1開(kāi)始計(jì)算的所以結(jié)果需要加1)
    divChilds = divNode.childNodes;
    for (i=0, len=divChilds.length; i<len; i++){
        if (divChilds[i].nodeName.toLowerCase() == "ul"){
            rangeIns.setEnd(divNode, i+1)
        }
    }
    document.write(rangeIns)
</script>

  • 3. 操作 DOM 范圍中的內(nèi)容

  • deleteContents()

    • Range.deleteContents() 移除來(lái)自 Document的Range 內(nèi)容。
  • extractContents()

    • Range.extractContents() 也會(huì)從文檔中移除范圍選區(qū)。但是會(huì)返回一個(gè)[object DocumentFragment] ,就是range中的范圍;
  • Range.cloneContents()

    • 返回 clone 的 Range。 返回是[object DocumentFragment] ;

  • 4.插入 DOM 范圍中的內(nèi)容

  • Range.insertNode(Node) 是在Range的起始位置插入節(jié)點(diǎn)。

  • 該方法將把指定的節(jié)點(diǎn)(和它的所有子孫節(jié)點(diǎn))插入文檔范圍的開(kāi)始點(diǎn)。當(dāng)該方法返回時(shí),當(dāng)前范圍將包括新插入的節(jié)點(diǎn)。如果 newNode 已經(jīng)是文檔的一部分,那么它將被從當(dāng)前位置刪除,然后重新插入范圍的開(kāi)始點(diǎn)。如果 newNodeDocumentFragment 節(jié)點(diǎn),那么插入的不是它自身,而是它的子孫節(jié)點(diǎn),按順序插入范圍的開(kāi)始點(diǎn)。

  • 如果包含當(dāng)前范圍的開(kāi)始點(diǎn)的節(jié)點(diǎn)是 Text 節(jié)點(diǎn),那么在發(fā)生插入操作前,它將被分割成兩個(gè)相鄰的節(jié)點(diǎn)。如果 newNode 是 Text 節(jié)點(diǎn),在插入文檔后,它不會(huì)與任何相鄰的 Text 節(jié)點(diǎn)合并。要合并相鄰的節(jié)點(diǎn),需要調(diào)用nodeObject.normalize()方法。

  • Range.surroundContents()方法將Range對(duì)象的內(nèi)容移動(dòng)到一個(gè)新的節(jié)點(diǎn)中, 并將這個(gè)新節(jié)點(diǎn)放回到range區(qū)域.如果選定的Range區(qū)域包含僅有一個(gè)節(jié)點(diǎn)標(biāo)簽的Text. 那標(biāo)簽將不會(huì)自動(dòng)成對(duì)生成,操作將失敗.

    <div id="div1"><p id="p1"><b id="myb">Hello</b> world!</p></div>

    <script>
        var range1 = document.createRange();
        range2 = document.createRange();
        p1 = document.getElementById("myb");
        range1.selectNode(p1.firstChild);                      //選中范圍是<b>標(biāo)簽
        var span = document.createElement("span");  //創(chuàng)建新節(jié)點(diǎn)
        span.style.backgroundColor = "yellow";           //給新節(jié)點(diǎn)添加樣式
        // span.innerText = "i am span";        ////就算給新節(jié)點(diǎn)添加文本, 也會(huì)被覆蓋
        // range1.insertNode(span)
        range1.surroundContents(span);     //1.提取范圍內(nèi)容;2.將新節(jié)點(diǎn)插入范圍的位置;3.把原來(lái)的范圍內(nèi)容插入新節(jié)點(diǎn)中;
  • 5. 折疊 DOM 范圍
  • Range.collapse(bool) 方法向邊界點(diǎn)折疊該 Range 。折疊后的 Range 為空,不包含節(jié)點(diǎn)內(nèi)容。
    • 參數(shù) true 表示折疊到范圍的起點(diǎn),參數(shù) false 表示折疊到范圍的終點(diǎn)。
  • 要確定 Range 是否已折疊,使用Range.collapsed 屬性。
range.collapse(true); //折疊到起點(diǎn)
alert(range.collapsed); //輸出 true
  • 6. 比較 DOM 范圍

    • Range.compareBoundaryPoints()
    • compareBoundaryPoints() 方法比較兩個(gè)范圍的位置。
    • compareBoundaryPoints(how,sourceRange)
    • how:聲明如何執(zhí)行比較操作(即比較哪些邊界點(diǎn))。它的合法值是 Range 接口定義的常量。
    • sourceRange 要與當(dāng)前范圍進(jìn)行比較的范圍。
    • 如果當(dāng)前范圍的指定邊界點(diǎn)位于 sourceRange 指定的邊界點(diǎn)之前,則返回 -1。如果指定的兩個(gè)邊界點(diǎn)相同,則返回 0。如果當(dāng)前范圍的邊界點(diǎn)位于 sourceRange 指定的邊界點(diǎn)之后,則返回 1。
      描述
    • 該方法將比較當(dāng)前范圍的邊界點(diǎn)和指定的 sourceRange 的邊界點(diǎn),并返回一個(gè)值,聲明它們?cè)谠次臋n中的相對(duì)位置。參數(shù) how 指定了比較兩個(gè)范圍的哪個(gè)邊界點(diǎn)。該參數(shù)的合法值和它們的含義如下:
      • Range.START_TO_START - 比較兩個(gè) Range 節(jié)點(diǎn)的開(kāi)始點(diǎn)
      • Range.END_TO_END - 比較兩個(gè) Range 節(jié)點(diǎn)的結(jié)束點(diǎn)
      • Range.START_TO_END - 用 sourceRange 的開(kāi)始點(diǎn)與當(dāng)前范圍的結(jié)束點(diǎn)比較
      • Range.END_TO_START - 用 sourceRange 的結(jié)束點(diǎn)與當(dāng)前范圍的開(kāi)始點(diǎn)比較
      • 常量 Range.START_TO_END 指定與當(dāng)前范圍的 end 點(diǎn)和 sourceRange 的 start 點(diǎn)進(jìn)行比較。同樣,常量 Range.END_TO_START 指定比較當(dāng)前范圍的 start 點(diǎn)和指定范圍的 end 點(diǎn)。
        My總結(jié):也就是前面的range和后面的range比較,START_TO_END,前面range的end和后面range的start比較
  • 7. 復(fù)制 DOM 范圍

    • 可以使用 cloneRange()方法復(fù)制范圍。這個(gè)方法會(huì)創(chuàng)建調(diào)用它的范圍的一個(gè)副本。
    • 新創(chuàng)建的范圍與原來(lái)的范圍包含相同的屬性,而修改它的端點(diǎn)不會(huì)影響原來(lái)的范圍。
var newRange = range.cloneRange();
  • 8. 清理 DOM 范圍
    • 在使用完范圍之后,最好是調(diào)用 detach()方法,以便從創(chuàng)建范圍的文檔中分離出該范圍。調(diào)用detach()之后,就可以放心地解除對(duì)范圍的引用,從而讓垃圾回收機(jī)制回收其內(nèi)存了。
range.detach(); //從文檔中分離
range = null; //解除引用
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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