選擇符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è)方法款票,最好是編寫一個(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>
- 在寫模式下,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> </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>本身欲芹。
- 在寫模式下卿啡,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ù)必須是下列值之一剑逃,注意,這些值都必須是小寫形式:
- "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è),就可以寫出如下所示的一個(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 寫入值時(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 屬性。
- 為了確鼻羝螅跨瀏覽器兼容饮戳,有必要編寫一個(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é)果完全一樣。
- 在寫模式下负拟,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.