【javascript】DOM擴(kuò)展

選擇符API

  • Selectors API(www.w3.org/TR/selectors-api/)是由W3C發(fā)起制定的一個(gè)標(biāo)準(zhǔn),致力于讓瀏覽器原生支持CSS 查詢。

1、querySelector()方法

  • querySelector()方法接收一個(gè)CSS選擇符,返回與該模式匹配的第一個(gè)元素,如果沒(méi)有找到匹配的元素,返回null。
//取得body 元素
var body = document.querySelector("body");
//取得ID 為"myDiv"的元素
var myDiv = document.querySelector("#myDiv");
//取得類為"selected"的第一個(gè)元素
var selected = document.querySelector(".selected");
//取得類為"button"的第一個(gè)圖像元素
var img = document.body.querySelector("img.button");

2、querySelectorAll()方法

querySelectorAll()方法接收的參數(shù)也是一個(gè)CSS 選擇符,這個(gè)方法返回的是一個(gè)NodeList 的實(shí)例。

//取得某<div>中的所有<em>元素(類似于getElementsByTagName("em"))
var ems = document.getElementById("myDiv").querySelectorAll("em");
//取得類為"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";
}

3、matchesSelector()方法

  • matchesSelector()方法接收一個(gè)參數(shù),即CSS選擇符,如果調(diào)用元素與該選擇符匹配,返回true;否則,返回false。
if (document.body.matchesSelector("body.page1")){
//true
}
  • IE 9+通過(guò)msMatchesSelector()支持該方法,F(xiàn)irefox3.6+通過(guò)mozMatchesSelector()支持該方法,Safari 5+和Chrome 通過(guò)webkitMatchesSelector()支持該方法。

  • 想使用這個(gè)方法,最好是編寫(xiě)一個(gè)包裝函數(shù)。

function matchesSelector(element, selector){
    if (element.matchesSelector){
        return element.matchesSelector(selector);
    } else if (element.msMatchesSelector){
        return element.msMatchesSelector(selector);
    } else if (element.mozMatchesSelector){
        return element.mozMatchesSelector(selector);
    } else if (element.webkitMatchesSelector){
        return element.webkitMatchesSelector(selector);
    } else {
        throw new Error("Not supported.");
    }
}
if (matchesSelector(document.body, "body.page1")){
//執(zhí)行操作
}

元素遍歷

  • 對(duì)于元素間的空格,IE9及之前版本不會(huì)返回文本節(jié)點(diǎn),而其他所有瀏覽器都會(huì)返回文本節(jié)點(diǎn)。這樣,就導(dǎo)致了在使用childNodes 和firstChild 等屬性時(shí)的行為不一致。

  • 為了彌補(bǔ)這一差異,而同時(shí)又保持DOM規(guī)范不變,ElementTraversal規(guī)范(www.w3.org/TR/ElementTraversal/)新定義了一組屬性。

  • Element Traversal API 為DOM元素添加了以下5 個(gè)屬性。

    • childElementCount:返回子元素(不包括文本節(jié)點(diǎn)和注釋)的個(gè)數(shù)。
    • firstElementChild:指向第一個(gè)子元素;firstChild 的元素版。
    • lastElementChild:指向最后一個(gè)子元素;lastChild 的元素版。
    • previousElementSibling:指向前一個(gè)同輩元素;previousSibling 的元素版。
    • nextElementSibling:指向后一個(gè)同輩元素;nextSibling 的元素版。
  • 利用這些元素不必?fù)?dān)心空白文本節(jié)點(diǎn),從而可以更方便地查找DOM 元素。

/**要跨瀏覽器遍歷某元素的所有子元素**/

//過(guò)去
var i,
len,
child = element.firstChild;
while(child != element.lastChild){
    if (child.nodeType == 1){ //檢查是不是元素
        processChild(child);
    }
    child = child.nextSibling;
}

//使用Element Traversal 新增的元素

var i,
len,
child = element.firstElementChild;
while(child != element.lastElementChild){
    processChild(child); //已知其是元素
    child = child.nextElementSibling;
}
  • 支持Element Traversal 規(guī)范的瀏覽器有IE 9+、Firefox 3.5+、Safari 4+、Chrome 和Opera 10+。

HTML5

  • HTML5 規(guī)范則圍繞如何使用新增標(biāo)記定義了大量JavaScript API。其中一些API 與DOM 重疊,定義了瀏覽器應(yīng)該支持的DOM擴(kuò)展。

1、與類相關(guān)的擴(kuò)充

(1)getElementsByClassName()方法、

//取得所有類中包含"username"和"current"的元素,類名的先后順序無(wú)所謂
var allCurrentUsernames = document.getElementsByClassName("username current");
//取得ID 為"myDiv"的元素中帶有類名"selected"的所有元素
var selected = document.getElementById("myDiv").getElementsByClassName("selected");

(2)classList 屬性

  • 在操作類名時(shí),需要通過(guò)className 屬性添加、刪除和替換類名。
<div class="bd user disabled">...</div>
  • 要從中刪除一個(gè)類名,需要把這三個(gè)類名拆開(kāi),刪除不想要的那個(gè),然后再把其他類名拼成一個(gè)新字符串。
//刪除"user"類
//首先,取得類名字符串并拆分成數(shù)組
var classNames = div.className.split(/\s+/);
//找到要?jiǎng)h的類名
var pos = -1,
i,
len;
for (i=0, len=classNames.length; i < len; i++){
    if (classNames[i] == "user"){
        pos = i;
        break;
    }
}
//刪除類名
classNames.splice(i,1);
//把剩下的類名拼成字符串并重新設(shè)置
div.className = classNames.join(" ");
  • HTML5 新增了一種操作類名的方式,可以讓操作更簡(jiǎn)單也更安全,那就是為所有元素添加
    classList 屬性。

  • classList 屬性是新集合類型DOMTokenList的實(shí)例,具有包含多少元素的length屬性,取得每個(gè)元素的item()方法,以及下列方法。

    • add(value):將給定的字符串值添加到列表中。如果值已經(jīng)存在,就不添加了。
    • contains(value):表示列表中是否存在給定的值,如果存在則返回true,否則返回false。
    • remove(value):從列表中刪除給定的字符串。
    • toggle(value):如果列表中已經(jīng)存在給定的值,刪除它;如果列表中沒(méi)有給定的值,添加它。
  • 極大地減少類似基本操作的復(fù)雜性

<div class="bd user disabled">...</div>
//刪除"user"類
div.classList.remove("user");

//刪除"disabled"類
div.classList.remove("disabled");

//添加"current"類
div.classList.add("current");

//切換"user"類
div.classList.toggle("user");

//確定元素中是否包含既定的類名
if (div.classList.contains("bd") && !div.classList.contains("disabled")){
    //執(zhí)行操作
)

//迭代類名
for (var i=0, len=div.classList.length; i < len; i++){
    doSomething(div.classList[i]);
}
  • 支持classList 屬性的瀏覽器有Firefox 3.6+和Chrome。

2、焦點(diǎn)管理

(1)document.activeElement

  • HTML5 也添加了輔助管理DOM 焦點(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
  • 默認(rèn)情況下,文檔剛剛加載完成時(shí),document.activeElement 中保存的是document.body 元素的引用。
  • 文檔加載期間,document.activeElement 的值為null。

(2)document.hasFocus()

  • 新增了document.hasFocus()方法,這個(gè)方法用于確定文檔是否獲得了焦點(diǎn)。
var button = document.getElementById("myButton");
button.focus();
alert(document.hasFocus()); //true

3、HTMLDocument的變化

(1)readyState 屬性

Document 的readyState 屬性有兩個(gè)可能的值:

  • loading,正在加載文檔;
  • complete,已經(jīng)加載完文檔。
if (document.readyState == "complete"){
//執(zhí)行操作
}

(2)兼容模式

  • document的compatMode的屬性,告訴開(kāi)發(fā)人員瀏覽器采用了哪種渲染模式。
  • 在標(biāo)準(zhǔn)模式下,document.compatMode的值等于"CSS1Compat",而在混雜模式下,document.compatMode 的值等于"BackCompat"。
if (document.compatMode == "CSS1Compat"){
    alert("Standards mode");
} else {
    alert("Quirks mode");
}

(3)head屬性

-作為對(duì)document.body 引用文檔的<body>元素的補(bǔ)充,HTML5 新增了document.head 屬性,引用文檔的<head>元素。

var head = document.head || document.getElementsByTagName("head")[0];

4、字符集屬性

(1)charset

  • charset 屬性表示文檔中實(shí)際使用的字符集,也可以用來(lái)指定新字符集。
  • 默認(rèn)情況下,這個(gè)屬性的值為"UTF-16",但可以通過(guò)<meta>元素、響應(yīng)頭部或直接設(shè)置charset 屬性修改這個(gè)值。
alert(document.charset); //"UTF-16"
document.charset = "UTF-8";

(2)defaultCharset

  • defaultCharset,表示根據(jù)默認(rèn)瀏覽器及操作系統(tǒng)的設(shè)置,當(dāng)前文檔默認(rèn)的字符集
    應(yīng)該是什么。
  • 如果文檔沒(méi)有使用默認(rèn)的字符集,那charset 和defaultCharset 屬性的值可能會(huì)不一
    樣。
if (document.charset != document.defaultCharset){
    alert("Custom character set being used.");
}

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>
var div = document.getElementById("myDiv");
//取得自定義屬性的值
var appId = div.dataset.appId;
var myName = div.dataset.myname;
//設(shè)置值
div.dataset.appId = 23456;
div.dataset.myname = "Michael";
//有沒(méi)有"myname"值呢?
if (div.dataset.myname){
    alert("Hello, " + div.dataset.myname);
}

6、插入標(biāo)記

(1)innerHTML屬性

  • 在讀模式下,innerHTML屬性返回與調(diào)用元素的所有子節(jié)點(diǎn)(包括元素、注釋和文本節(jié)點(diǎn))對(duì)應(yīng)的HTML 標(biāo)記。
<div id="content">
    <p>This is a <strong>paragraph</strong> with a list following it.</p>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
</div>
  • 對(duì)于上面的div元素來(lái)說(shuō),它的innerHTML 屬性會(huì)返回如下字符串。
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>
  • 在寫(xiě)模式下,innerHTML 會(huì)根據(jù)指定的值創(chuàng)建新的DOM樹(shù),然后用這個(gè)DOM樹(shù)完全
    替換調(diào)用元素原先的所有子節(jié)點(diǎn)。
div.innerHTML = "_<script defer>alert('hi');<\/script>";
div.innerHTML = "<div>&nbsp;</div><script defer>alert('hi');<\/script>";
div.innerHTML = "<input type=\"hidden\"><script defer>alert('hi');<\/script>";

(2)outerHTML屬性

  • 在讀模式下,outerHTML 返回調(diào)用它的元素及所有子節(jié)點(diǎn)的HTML 標(biāo)簽。
<div id="content">
    <p>This is a <strong>paragraph</strong> with a list following it.</p>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
</div>
  • 如果在<div>元素上調(diào)用outerHTML,會(huì)返回與上面相同的代碼,包括<div>本身。
  • 在寫(xiě)模式下,outerHTML會(huì)根據(jù)指定的HTML字符串創(chuàng)建新的DOM子樹(shù),然后用這個(gè)DOM子樹(shù)完全替換調(diào)用元素。
  • 使用outerHTML 屬性以下面這種方式設(shè)置值:
div.outerHTML = "<p>This is a paragraph.</p>";

//DOM 腳本代碼
var p = document.createElement("p");
p.appendChild(document.createTextNode("This is a paragraph."));
div.parentNode.replaceChild(p, div);

(3)insertAdjacentHTML()方法

  • insertAdjacentHTML()方法接收兩個(gè)參數(shù):插入位置和要插入的HTML 文本。

  • 第一個(gè)參數(shù)必須是下列值之一,注意,這些值都必須是小寫(xiě)形式:

    • "beforebegin",在當(dāng)前元素之前插入一個(gè)緊鄰的同輩元素;
    • "afterbegin",在當(dāng)前元素之下插入一個(gè)新的子元素或在第一個(gè)子元素之前再插入新的子元素;
    • "beforeend",在當(dāng)前元素之下插入一個(gè)新的子元素或在最后一個(gè)子元素之后再插入新的子元素;
    • "afterend",在當(dāng)前元素之后插入一個(gè)緊鄰的同輩元素。
  • 第二個(gè)參數(shù)是一個(gè)HTML 字符串,如果瀏覽器無(wú)法解析該字符串,就會(huì)拋出錯(cuò)誤。

//作為前一個(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)題

  • 不可避免地,創(chuàng)建和銷毀HTML 解析器也會(huì)帶來(lái)性能損失,所以最好能夠?qū)⒃O(shè)置innerHTML
    或outerHTML 的次數(shù)控制在合理的范圍內(nèi)。
for (var i=0, len=values.length; i < len; i++){
    ul.innerHTML += "<li>" + values[i] + "</li>"; //要避免這種頻繁操作??!
}

/**
最好的做法是單獨(dú)構(gòu)建字符串,然后再一次
性地將結(jié)果字符串賦值給innerHTML
**/

var itemsHtml = "";
for (var i=0, len=values.length; i < len; i++){
    itemsHtml += "<li>" + values[i] + "</li>";
}
ul.innerHTML = itemsHtml;

7、scrollIntoView()方法

  • scrollIntoView()可以在所有HTML元素上調(diào)用,通過(guò)滾動(dòng)瀏覽器窗口或某個(gè)容器元素,調(diào)用元素就可以出現(xiàn)在視口中。
  • 如果給這個(gè)方法傳入true作為參數(shù),或者不傳入任何參數(shù),那么窗口滾動(dòng)之后會(huì)讓調(diào)用元素的頂部與視口頂部盡可能平齊。
  • 如果傳入false 作為參數(shù),調(diào)用元素會(huì)盡可能全部出現(xiàn)在視口中,(可能的話,調(diào)用元素的底部會(huì)與視口頂部平齊。)不過(guò)頂部不一定平齊。
//讓元素可見(jiàn)
document.forms[0].scrollIntoView();

專有擴(kuò)展

(1)文檔模式

  • 要強(qiáng)制瀏覽器以某種模式渲染頁(yè)面,可以使用HTTP頭部信息X-UA-Compatible,或通過(guò)等價(jià)的<meta>標(biāo)簽來(lái)設(shè)置:
<meta http-equiv="X-UA-Compatible" content="IE=IEVersion">

(2)children屬性

  • 這個(gè)屬性是HTMLCollection 的實(shí)例,只包含元素中同樣還是元素的子節(jié)點(diǎn)。
var childCount = element.children.length;
var firstChild = element.children[0];

(3)contains()方法

  • contains()方法接收一個(gè)參數(shù),即要檢測(cè)的后代節(jié)點(diǎn)。如果被檢測(cè)的節(jié)點(diǎn)是后代節(jié)點(diǎn),
    該方法返回true;否則,返回false。
alert(document.documentElement.contains(document.body)); //true
  • 使用DOM Level 3 compareDocumentPosition()也能夠確定節(jié)點(diǎn)間的關(guān)系。返回一個(gè)表示該關(guān)系的位掩碼( bitmask)。
  • 支持這個(gè)方法的瀏覽器有IE9+、Firefox、Safari、Opera 9.5+和Chrome。
  • 下表列出了這個(gè)位掩碼的值。
掩碼 節(jié)點(diǎn)關(guān)系
1 無(wú)關(guān)(給定的節(jié)點(diǎn)不在當(dāng)前文檔中)
2 居前(給定的節(jié)點(diǎn)在DOM樹(shù)中位于參考節(jié)點(diǎn)之前)
4 居后(給定的節(jié)點(diǎn)在DOM樹(shù)中位于參考節(jié)點(diǎn)之后)
8 包含(給定的節(jié)點(diǎn)是參考節(jié)點(diǎn)的祖先)
16 被包含(給定的節(jié)點(diǎn)是參考節(jié)點(diǎn)的后代)
  • 可以對(duì)compareDocumentPosition()的結(jié)果執(zhí)行按位與,以確定參考節(jié)點(diǎn)(調(diào)用compareDocumentPosition()方法的當(dāng)前節(jié)點(diǎn))是否包含給定的節(jié)點(diǎn)(傳入的節(jié)點(diǎn))。
var result = document.documentElement.compareDocumentPosition(document.body);
alert(!!(result & 16));
  • 使用一些瀏覽器及能力檢測(cè),就可以寫(xiě)出如下所示的一個(gè)通用的contains 函數(shù):
function contains(refNode, otherNode){
    if (typeof refNode.contains == "function" &&
    (!client.engine.webkit || client.engine.webkit >= 522)){
    /**檢查了當(dāng)前瀏覽器所用的WebKit 版本號(hào),如果瀏覽器是WebKit 且至少是Safari 3(WebKit版本號(hào)為522 或更高)**/
        return refNode.contains(otherNode);
    } else if (typeof refNode.compareDocumentPosition == "function"){
        return !!(refNode.compareDocumentPosition(otherNode) & 16);
    } else {
        var node = otherNode.parentNode;
        do {
            if (node === refNode){
                return true;
            } else {
                node = node.parentNode;
            }
        } while (node !== null);
        return false;
    }
}

(4)插入文本

  • 在通過(guò)innerText 讀取值時(shí),它會(huì)按照由淺入深的順序,將子文檔樹(shù)中的所有文本拼接起來(lái)。
<div id="content">
    <p>This is a <strong>paragraph</strong> with a list following it.</p>
    <ul>
        <li>Item 1</li>
        <li>Item 2</li>
        <li>Item 3</li>
    </ul>
</div>
  • 對(duì)于這個(gè)例子中的<div>元素而言,其innerText 屬性會(huì)返回下列字符串
This is a paragraph with a list following it.
Item 1
Item 2
Item 3
  • 在通過(guò)innerText 寫(xiě)入值時(shí),結(jié)果會(huì)刪除元素的所有子節(jié)點(diǎn),插入包含相應(yīng)文本值的文本節(jié)點(diǎn)。
div.innerText = "Hello world!";
  • 執(zhí)行這行代碼后,頁(yè)面的HTML 代碼就會(huì)變成如下所示。
<div id="content">Hello world!</div>
  • Firefox 不支持innerText,支持作用類似的textContent 屬性。
  • 為了確保跨瀏覽器兼容,有必要編寫(xiě)一個(gè)類似于下面的函數(shù)來(lái)檢測(cè)可以使用哪個(gè)屬性。
function getInnerText(element){
    return (typeof element.textContent == "string") ?
        element.textContent : element.innerText;
}
function setInnerText(element, text){
    if (typeof element.textContent == "string"){
        element.textContent = text;
    } else {
        element.innerText = text;
    }
}
setInnerText(div, "Hello world!");
alert(getInnerText(div)); //"Hello world!"
  • 在讀取文本值時(shí),outerText 與innerText 的結(jié)果完全一樣。
  • 在寫(xiě)模式下,outerText就完全不同了:outerText不只是替換調(diào)用它的元素的子節(jié)點(diǎn),而是會(huì)替換整個(gè)元素(包括子節(jié)點(diǎn))。
div.outerText = "Hello world!";

//這行代碼實(shí)際上相當(dāng)于如下兩行代碼:
var text = document.createTextNode("Hello world!");
div.parentNode.replaceChild(text, div);

滾動(dòng)

  • scrollIntoViewIfNeeded(alignCenter):只在當(dāng)前元素在視口中不可見(jiàn)的情況下,才滾
    動(dòng)瀏覽器窗口或容器元素,最終讓它可見(jiàn)。如果當(dāng)前元素在視口中可見(jiàn),這個(gè)方法什么也不做。如果將可選的alignCenter參數(shù)設(shè)置為true,則表示盡量將元素顯示在視口中部(垂直方向)。
  • scrollByLines(lineCount):將元素的內(nèi)容滾動(dòng)指定的行高,lineCount 值可以是正值,
    也可以是負(fù)值。
  • scrollByPages(pageCount):將元素的內(nèi)容滾動(dòng)指定的頁(yè)面高度,具體高度由元素的高度決定。

The scrollByLines method is only supported by Firefox, use the cross-browser scrollBy method instead.

好好學(xué)習(xí)
?著作權(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)容

  • 一、JS前言 (1)認(rèn)識(shí)JS 也許你已經(jīng)了解HTML標(biāo)記(也稱為結(jié)構(gòu)),知道了CSS樣式(也稱為表示),會(huì)使用HT...
    凜0_0閱讀 2,901評(píng)論 0 8
  • 第1章 認(rèn)識(shí)JS JavaScript能做什么?1.增強(qiáng)頁(yè)面動(dòng)態(tài)效果(如:下拉菜單、圖片輪播、信息滾動(dòng)等)2.實(shí)現(xiàn)...
    mo默22閱讀 1,492評(píng)論 0 5
  • DOM 變化 如何確認(rèn)瀏覽器是否支持 DOM 2 和 DOM 3 新增的模塊:var supportsDOM2Co...
    云之外閱讀 518評(píng)論 0 0
  • 早上才知道host的大兒子今天生日 從9點(diǎn)到1點(diǎn),一直在說(shuō)說(shuō)說(shuō)聊聊聊,在lucas的結(jié)他伴奏下雖然沒(méi)有啤酒,燈光燦...
    freeeerf閱讀 303評(píng)論 0 0
  • 簡(jiǎn)介CSS多列布局繼承自塊級(jí)布局模式,允許簡(jiǎn)單地定義多列文本。當(dāng)閱讀文字的時(shí)候,從一行末尾移動(dòng)到下一行開(kāi)始處,容易...
    老95閱讀 627評(píng)論 0 0

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