JavaScript document節(jié)點(diǎn)

2021-09-15 15:15 更新

document節(jié)點(diǎn)概述

document節(jié)點(diǎn)是文檔的根節(jié)點(diǎn),每張網(wǎng)頁(yè)都有自己的document節(jié)點(diǎn)。window.document屬性就指向這個(gè)節(jié)點(diǎn)。也就是說(shuō),只要瀏覽器開(kāi)始載入HTML文檔,這個(gè)節(jié)點(diǎn)對(duì)象就開(kāi)始存在了,可以直接調(diào)用。

document節(jié)點(diǎn)有不同的辦法可以獲取。

  • 對(duì)于正常的網(wǎng)頁(yè),直接使用document或window.document。
  • 對(duì)于iframe載入的網(wǎng)頁(yè),使用iframe節(jié)點(diǎn)的contentDocument屬性。
  • 對(duì)Ajax操作返回的文檔,使用XMLHttpRequest對(duì)象的responseXML屬性。
  • 對(duì)于某個(gè)節(jié)點(diǎn)包含的文檔,使用該節(jié)點(diǎn)的ownerDocument屬性。

上面這四種document節(jié)點(diǎn),都部署了Document接口,因此有共同的屬性和方法。當(dāng)然,各自也有一些自己獨(dú)特的屬性和方法,比如HTML和XML文檔的document節(jié)點(diǎn)就不一樣。

document節(jié)點(diǎn)的屬性

document節(jié)點(diǎn)有很多屬性,用得比較多的是下面這些。

doctype,documentElement,defaultView,body,head,activeElement

以下屬性指向文檔內(nèi)部的某個(gè)節(jié)點(diǎn)。

(1)doctype

對(duì)于HTML文檔來(lái)說(shuō),document對(duì)象一般有兩個(gè)子節(jié)點(diǎn)。第一個(gè)子節(jié)點(diǎn)是document.doctype,它是一個(gè)對(duì)象,包含了當(dāng)前文檔類型(Document Type Declaration,簡(jiǎn)寫(xiě)DTD)信息。對(duì)于HTML5文檔,該節(jié)點(diǎn)就代表。如果網(wǎng)頁(yè)沒(méi)有聲明DTD,該屬性返回null。

var doctype = document.doctype;

doctype // "<!DOCTYPE html>"
doctype.name // "html"

document.firstChild通常就返回這個(gè)節(jié)點(diǎn)。

(2)documentElement

document.documentElement屬性,表示當(dāng)前文檔的根節(jié)點(diǎn)(root)。它通常是document節(jié)點(diǎn)的第二個(gè)子節(jié)點(diǎn),緊跟在document.doctype節(jié)點(diǎn)后面。

對(duì)于HTML網(wǎng)頁(yè),該屬性返回HTML節(jié)點(diǎn),代表。

(3)defaultView

defaultView屬性,在瀏覽器中返回document對(duì)象所在的window對(duì)象,否則返回null。

var win = document.defaultView;

(4)body

body屬性返回當(dāng)前文檔的body或frameset節(jié)點(diǎn),如果不存在這樣的節(jié)點(diǎn),就返回null。這個(gè)屬性是可寫(xiě)的,如果對(duì)其寫(xiě)入一個(gè)新的節(jié)點(diǎn),會(huì)導(dǎo)致原有的所有子節(jié)點(diǎn)被移除。

(4)head

head屬性返回當(dāng)前文檔的head節(jié)點(diǎn)。如果當(dāng)前文檔有多個(gè)head,則返回第一個(gè)。

document.head === document.querySelector("head") 

(5)activeElement

activeElement屬性返回當(dāng)前文檔中獲得焦點(diǎn)的那個(gè)元素。用戶通常可以使用tab鍵移動(dòng)焦點(diǎn),使用空格鍵激活焦點(diǎn),比如如果焦點(diǎn)在一個(gè)鏈接上,此時(shí)按一下空格鍵,就會(huì)跳轉(zhuǎn)到該鏈接。

documentURI,URL,domain,lastModified,location,referrer,title,characterSet

以下屬性返回文檔信息。

(1)documentURI,URL

documentURI屬性和URL屬性都返回當(dāng)前文檔的網(wǎng)址。不同之處是documentURI屬性是所有文檔都具備的,URL屬性則是HTML文檔獨(dú)有的。

(2)domain

domain屬性返回當(dāng)前文檔的域名。比如,某張網(wǎng)頁(yè)的網(wǎng)址是 http://www.example.com/hello.html,domain屬性就等于 www.example.com 。如果無(wú)法獲取域名,該屬性返回null。

var badDomain = "www.example.xxx";

if (document.domain === badDomain)
  window.close();

上面代碼判斷,如果當(dāng)前域名等于指定域名,則關(guān)閉窗口。

二級(jí)域名的情況下,domain屬性可以設(shè)置為對(duì)應(yīng)的一級(jí)域名。比如,當(dāng)前域名是sub.example.com,則domain屬性可以設(shè)置為example.com。除此之外的寫(xiě)入,都是不可以的。

(3)lastModified

lastModified屬性返回當(dāng)前文檔最后修改的時(shí)間戳,格式為字符串。

document.lastModified
// Tuesday, July 10, 2001 10:19:42

注意,lastModified屬性的值是字符串,所以不能用來(lái)直接比較,兩個(gè)文檔誰(shuí)的日期更新,需要用Date.parse方法轉(zhuǎn)成時(shí)間戳格式,才能進(jìn)行比較。

if (Date.parse(doc1.lastModified) > Date.parse(doc2.lastModified)) {
  // ...
}

(4)location

location屬性返回一個(gè)只讀對(duì)象,提供了當(dāng)前文檔的URL信息。

// 假定當(dāng)前網(wǎng)址為http://user:passwd@www.example.com:4097/path/a.html?x=111#part1

document.location.href // "http://user:passwd@www.example.com:4097/path/a.html?x=111#part1"
document.location.protocol // "http:"
document.location.host // "www.example.com:4097"
document.location.hostname // "www.example.com"
document.location.port // "4097"
document.location.pathname // "/path/a.html"
document.location.search // "?x=111"
document.location.hash // "#part1"
document.location.user // "user"
document.location.password // "passed"

// 跳轉(zhuǎn)到另一個(gè)網(wǎng)址
document.location.assign('http://www.google.com')
// 優(yōu)先從服務(wù)器重新加載
document.location.reload(true)
// 優(yōu)先從本地緩存重新加載(默認(rèn)值)
document.location.reload(false)
// 跳轉(zhuǎn)到另一個(gè)網(wǎng)址,但當(dāng)前文檔不保留在history對(duì)象中,
// 即無(wú)法用后退按鈕,回到當(dāng)前文檔
document.location.assign('http://www.google.com')
// 將location對(duì)象轉(zhuǎn)為字符串,等價(jià)于document.location.href
document.location.toString()

雖然location屬性返回的對(duì)象是只讀的,但是可以將URL賦值給這個(gè)屬性,網(wǎng)頁(yè)就會(huì)自動(dòng)跳轉(zhuǎn)到指定網(wǎng)址。

document.location = 'http://www.example.com';
// 等價(jià)于
document.location.;

document.location屬性與window.location屬性等價(jià),歷史上,IE曾經(jīng)不允許對(duì)document.location賦值,為了保險(xiǎn)起見(jiàn),建議優(yōu)先使用window.location。如果只是單純地獲取當(dāng)前網(wǎng)址,建議使用document.URL。

(5)referrer

referrer屬性返回一個(gè)字符串,表示前文檔的訪問(wèn)來(lái)源,如果是無(wú)法獲取來(lái)源或是用戶直接鍵入網(wǎng)址,而不是從其他網(wǎng)頁(yè)點(diǎn)擊,則返回一個(gè)空字符串。

(6)title

title屬性返回當(dāng)前文檔的標(biāo)題,該屬性是可寫(xiě)的。

document.title = '新標(biāo)題';

(7)characterSet

characterSet屬性返回渲染當(dāng)前文檔的字符集,比如UTF-8、ISO-8859-1。

readyState,designModed

以下屬性與文檔行為有關(guān)。

(1)readyState

readyState屬性返回當(dāng)前文檔的狀態(tài),共有三種可能的值,加載HTML代碼階段(尚未完成解析)是“l(fā)oading”,加載外部資源階段是“interactive”,全部加載完成是“complete”。

(2)designModed

designMode屬性控制當(dāng)前document是否可編輯。通常會(huì)打開(kāi)iframe的designMode屬性,將其變?yōu)橐粋€(gè)所見(jiàn)即所得的編輯器。

iframe_node.contentDocument.designMode = "on";

implementation,compatMode

以下屬性返回文檔的環(huán)境信息。

(1)implementation

implementation屬性返回一個(gè)對(duì)象,用來(lái)甄別當(dāng)前環(huán)境部署了哪些DOM相關(guān)接口。implementation屬性的hasFeature方法,可以判斷當(dāng)前環(huán)境是否部署了特定版本的特定接口。

document.implementation.hasFeature( 'HTML, 2.0 )
// true

document.implementation.hasFeature('MutationEvents','2.0')
// true

上面代碼表示,當(dāng)前環(huán)境部署了DOM HTML 2.0版和MutationEvents的2.0版。

(2)compatMode

compatMode屬性返回瀏覽器處理文檔的模式,可能的值為BackCompat(向后兼容模式)和 CSS1Compat(嚴(yán)格模式)。

anchors,embeds,forms,images,links,scripts,styleSheets

以下屬性返回文檔內(nèi)部特定元素的集合(即HTMLCollection對(duì)象,詳見(jiàn)下文)。這些集合都是動(dòng)態(tài)的,原節(jié)點(diǎn)有任何變化,立刻會(huì)反映在集合中。

(1)anchors

anchors屬性返回網(wǎng)頁(yè)中所有的a節(jié)點(diǎn)元素。注意,只有指定了name屬性的a元素,才會(huì)包含在anchors屬性之中。

(2)embeds

embeds屬性返回網(wǎng)頁(yè)中所有嵌入對(duì)象,即embed標(biāo)簽,返回的格式為類似數(shù)組的對(duì)象(nodeList)。

(3)forms

forms屬性返回頁(yè)面中所有表單。

var selectForm = document.forms[index];
var selectFormElement = document.forms[index].elements[index];

上面代碼獲取指定表單的指定元素。

(4)images

images屬性返回頁(yè)面所有圖片元素(即img標(biāo)簽)。

var ilist = document.images;

for(var i = 0; i < ilist.length; i++) {
  if(ilist[i].src == "banner.gif") {
    // ...
  }
}

上面代碼在所有img標(biāo)簽中,尋找特定圖片。

(4)links

links屬性返回當(dāng)前文檔所有的鏈接元素(即a標(biāo)簽,或者說(shuō)具有href屬性的元素)。

(5)scripts

scripts屬性返回當(dāng)前文檔的所有腳本(即script標(biāo)簽)。

var scripts = document.scripts;
if (scripts.length !== 0 ) {
  console.log("當(dāng)前網(wǎng)頁(yè)有腳本");
}

(6)styleSheets

styleSheets屬性返回一個(gè)類似數(shù)組的對(duì)象,包含了當(dāng)前網(wǎng)頁(yè)的所有樣式表。該屬性提供了樣式表操作的接口。然后,每張樣式表對(duì)象的cssRules屬性,返回該樣式表的所有CSS規(guī)則。這又方便了操作具體的CSS規(guī)則。

var allSheets = [].slice.call(document.styleSheets);

上面代碼中,使用slice方法將document.styleSheets轉(zhuǎn)為數(shù)組,以便于進(jìn)一步處理。

cookie

(1)概述

cookie屬性返回當(dāng)前網(wǎng)頁(yè)的cookie。

// 讀取當(dāng)前網(wǎng)頁(yè)的所有cookie
allCookies = document.cookie;

該屬性是可寫(xiě)的,但是一次只能寫(xiě)入一個(gè)cookie,也就是說(shuō)寫(xiě)入并不是覆蓋,而是添加。另外,cookie的值必須對(duì)分號(hào)、逗號(hào)和空格進(jìn)行轉(zhuǎn)義。

// 寫(xiě)入一個(gè)新cookie
document.cookie = "test1=hello";
// 再寫(xiě)入一個(gè)cookie
document.cookie = "test2=world";

document.cookie
// test1=hello;test2=world

cookie屬性的讀寫(xiě)操作含義不同,跟服務(wù)器與瀏覽器的通信格式有關(guān)。瀏覽器向服務(wù)器發(fā)送cookie,是一次性所有cookie全部發(fā)送。

GET /sample_page.html HTTP/1.1
Host: www.example.org
Cookie: cookie_name1=cookie_value1; cookie_name2=cookie_value2
Accept: */*

服務(wù)器告訴瀏覽器需要儲(chǔ)存cookie,則是分行指定。

HTTP/1.0 200 OK
Content-type: text/html
Set-Cookie: cookie_name1=cookie_value1
Set-Cookie: cookie_name2=cookie_value2; expires=Sun, 16 Jul 3567 06:23:41 GMT

cookie的值可以用encodeURIComponent方法進(jìn)行處理,對(duì)逗號(hào)、分號(hào)、空格進(jìn)行轉(zhuǎn)義(這些符號(hào)都不允許作為cookie的值)。

(2)cookie的屬性

除了cookie本身的內(nèi)容,還有一些可選的屬性也是可以寫(xiě)入的,它們都必須以分號(hào)開(kāi)頭。

Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
  • ; path=path,指定路徑,必須是絕對(duì)路徑(比如'/','/mydir'),如果未指定,默認(rèn)為設(shè)定該cookie的路徑。只有path屬性匹配向服務(wù)器發(fā)送的路徑,cookie才會(huì)發(fā)送。這里的匹配不是絕對(duì)匹配,而是從根路徑開(kāi)始,只要path屬性匹配發(fā)送路徑的一部分,就可以發(fā)送。比如,path屬性等于/blog,則發(fā)送路徑是/blog或者/blogroll,cookie都會(huì)發(fā)送。path屬性生效的前提是domain屬性匹配。

  • ; domain=domain,指定cookie所在的域名,比如'example.com','.example.com'(這種寫(xiě)法將對(duì)所有子域名生效)、'subdomain.example.com'。如果未指定,默認(rèn)為設(shè)定該cookie的域名。所指定的域名必須是當(dāng)前發(fā)送cookie的域名的一部分,比如當(dāng)前訪問(wèn)的域名是example.com,就不能將其設(shè)為google.com。只有訪問(wèn)的域名匹配domain屬性,cookie才會(huì)發(fā)送到服務(wù)器。

  • ; max-age=max-age-in-seconds,指定cookie有效期,比如606024*365(即一年31536e3秒)。

  • ; expires=date-in-GMTString-format,指定cookie過(guò)期時(shí)間,日期格式等同于Date.toUTCString()的格式。如果不設(shè)置該屬性,則cookie只在當(dāng)前會(huì)話(session)有效,瀏覽器窗口一旦關(guān)閉,當(dāng)前session結(jié)束,該cookie就會(huì)被刪除。瀏覽器根據(jù)本地時(shí)間,決定cookie是否過(guò)期,由于本地時(shí)間是不精確的,所以沒(méi)有辦法保證cookie一定會(huì)在服務(wù)器指定的時(shí)間過(guò)期。

  • ; secure,指定cookie只能在加密協(xié)議HTTPS下發(fā)送到服務(wù)器。該屬性只是一個(gè)開(kāi)關(guān),不需要設(shè)定值。在HTTPS協(xié)議下設(shè)定的cookie,該開(kāi)關(guān)自動(dòng)打開(kāi)。

以上屬性可以同時(shí)設(shè)置一個(gè)或多個(gè),也沒(méi)有次序的要求。如果服務(wù)器想改變一個(gè)早先設(shè)置的cookie,必須同時(shí)滿足四個(gè)條件:cookie的名字、domain、path和secure。也就是說(shuō),如果原始的cookie是用如下的Set-Cookie頭命令設(shè)置的。

Set-Cookie: key1=value1; domain=example.com; path=/blog

改變上面這個(gè)cookie的值,就必須使用同樣的Set-Cookie命令。

Set-Cookie: key1=value2; domain=example.com; path=/blog

只要有一個(gè)屬性不同,就會(huì)生成一個(gè)全新的cookie,而不是替換掉原來(lái)那個(gè)cookie。

Set-Cookie: key1=value2; domain=example.com; path=/

上面的命令設(shè)置了一個(gè)全新的同名cookie。下一次訪問(wèn)example.com/blog的時(shí)候,瀏覽器將向服務(wù)器發(fā)送兩個(gè)同名的cookie。

Cookie: key1=value1; key1=value2

上面代碼的兩個(gè)cookie是同名的,匹配越精確的cookie排在越前面。

var str = 'someCookieName=true';
str += '; expires=Fri, 31 Dec 9999 23:59:59 GMT';
str += '; path=/';

document.cookie = str;

另外,上面這些cookie屬性只能用來(lái)設(shè)置cookie。一旦設(shè)置完成,就沒(méi)有辦法從某個(gè)cookie讀取這些屬性的值。

刪除一個(gè)cookie的簡(jiǎn)便方法,就是設(shè)置expires屬性等于0。

(3)cookie的限制

瀏覽器對(duì)cookie的數(shù)量和長(zhǎng)度有限制,但是每個(gè)瀏覽器的規(guī)定是不一樣的。

  • IE6:每個(gè)域名20個(gè)cookie。
  • IE7,IE8,F(xiàn)irefox:每個(gè)域名50個(gè)cookie
  • Safari,Chrome:沒(méi)有域名數(shù)量的限制。

所有cookie的累加長(zhǎng)度限制為4KB。超過(guò)這個(gè)長(zhǎng)度的cookie,將被忽略,不會(huì)被設(shè)置。

由于cookie存在數(shù)量限制,有時(shí)為了規(guī)避限制,可以將cookie設(shè)置成下面的形式。

name=a=b&c=d&e=f&g=h

上面代碼實(shí)際上是設(shè)置了一個(gè)cookie,但是這個(gè)cookie內(nèi)部使用&符號(hào),設(shè)置了多部分的內(nèi)容。因此,可以在一個(gè)cookie里面,通過(guò)自行解析,可以得到多個(gè)鍵值對(duì)。這樣就規(guī)避了cookie的數(shù)量限制。

(4)HTTP-Only cookie

設(shè)置cookie的時(shí)候,如果服務(wù)器加上了HTTPOnly屬性,則這個(gè)cookie無(wú)法被JavaScript讀取(即document.cookie不會(huì)返回這個(gè)cookie的值),只用于向服務(wù)器發(fā)送。

Set-Cookie: key=value; HttpOnly

上面的這個(gè)cookie將無(wú)法用JavaScript獲取。進(jìn)行AJAX操作時(shí),getAllResponseHeaders方法或getResponseHeader方法也不會(huì)顯示這個(gè)頭命令。

document對(duì)象的方法

document對(duì)象主要有以下一些方法。

open(),close(),write(),writeln()

document.open方法用于新建一個(gè)文檔,供write方法寫(xiě)入內(nèi)容。它實(shí)際上等于清除當(dāng)前文檔,重新寫(xiě)入內(nèi)容。不要將此方法與window.open()混淆,后者用來(lái)打開(kāi)一個(gè)新窗口,與當(dāng)前文檔無(wú)關(guān)。

document.close方法用于關(guān)閉open方法所新建的文檔。一旦關(guān)閉,write方法就無(wú)法寫(xiě)入內(nèi)容了。如果再調(diào)用write方法,就等同于又調(diào)用open方法,新建一個(gè)文檔,再寫(xiě)入內(nèi)容。

document.write方法用于向當(dāng)前文檔寫(xiě)入內(nèi)容。只要當(dāng)前文檔還沒(méi)有用close方法關(guān)閉,它所寫(xiě)入的內(nèi)容就會(huì)追加在已有內(nèi)容的后面。

// 頁(yè)面顯示“helloworld”
document.open();
document.write("hello");
document.write("world");
document.close();

如果頁(yè)面已經(jīng)渲染完成(DOMContentLoaded事件發(fā)生之后),再調(diào)用write方法,它會(huì)先調(diào)用open方法,擦除當(dāng)前文檔所有內(nèi)容,然后再寫(xiě)入。

document.addEventListener("DOMContentLoaded", function(event) {
  document.write('<p>Hello World!</p>');
});

// 等同于

document.addEventListener("DOMContentLoaded", function(event) {
  document.open();
  document.write('<p>Hello World!</p>');
  document.close();
});

如果在頁(yè)面渲染過(guò)程中調(diào)用write方法,并不會(huì)調(diào)用open方法。(可以理解成,open方法已調(diào)用,但close方法還未調(diào)用。)

<html>
<body>
hello
<script type="text/javascript">
  document.write("world")
</script>
</body>
</html>

在瀏覽器打開(kāi)上面網(wǎng)頁(yè),將會(huì)顯示“hello world”。

需要注意的是,雖然調(diào)用close方法之后,無(wú)法再用write方法寫(xiě)入內(nèi)容,但這時(shí)當(dāng)前頁(yè)面的其他DOM節(jié)點(diǎn)還是會(huì)繼續(xù)加載。

<html>
<head>
<title>write example</title>
<script type="text/javascript">
  document.open();
  document.write("hello");
  document.close();
</script>
</head>
<body>
world
</body>
</html>

在瀏覽器打開(kāi)上面網(wǎng)頁(yè),將會(huì)顯示“hello world”。

總之,除了某些特殊情況,應(yīng)該盡量避免使用document.write這個(gè)方法。

document.writeln方法與write方法完全一致,除了會(huì)在輸出內(nèi)容的尾部添加換行符。

document.write(1);
document.write(2);
// 12

document.writeln(1);
document.writeln(2);
// 1
// 2
//

注意,writeln方法添加的是ASCII碼的換行符,渲染成HTML網(wǎng)頁(yè)時(shí)不起作用。

hasFocus()

document.hasFocus方法返回一個(gè)布爾值,表示當(dāng)前文檔之中是否有元素被激活或獲得焦點(diǎn)。

focused = document.hasFocus();

注意,有焦點(diǎn)的文檔必定被激活(active),反之不成立,激活的文檔未必有焦點(diǎn)。比如如果用戶點(diǎn)擊按鈕,從當(dāng)前窗口跳出一個(gè)新窗口,該新窗口就是激活的,但是不擁有焦點(diǎn)。

querySelector(),getElementById(),querySelectorAll(),getElementsByTagName(),getElementsByClassName(),getElementsByName(),elementFromPoint()

以下方法用來(lái)選中當(dāng)前文檔中的元素。

(1)querySelector()

querySelector方法返回匹配指定的CSS選擇器的元素節(jié)點(diǎn)。如果有多個(gè)節(jié)點(diǎn)滿足匹配條件,則返回第一個(gè)匹配的節(jié)點(diǎn)。如果沒(méi)有發(fā)現(xiàn)匹配的節(jié)點(diǎn),則返回null。

var el1 = document.querySelector(".myclass");
var el2 = document.querySelector('#myParent > [ng-click]');

querySelector方法無(wú)法選中CSS偽元素。

(2)getElementById()

getElementById方法返回匹配指定ID屬性的元素節(jié)點(diǎn)。如果沒(méi)有發(fā)現(xiàn)匹配的節(jié)點(diǎn),則返回null。

var elem = document.getElementById("para1");

注意,在搜索匹配節(jié)點(diǎn)時(shí),ID屬性是大小寫(xiě)敏感的。比如,如果某個(gè)節(jié)點(diǎn)的ID屬性是main,那么document.getElementById("Main")將返回null,而不是指定節(jié)點(diǎn)。

getElementById方法與querySelector方法都能獲取元素節(jié)點(diǎn),不同之處是querySelector方法的參數(shù)使用CSS選擇器語(yǔ)法,getElementById方法的參數(shù)是HTML標(biāo)簽元素的id屬性。

document.getElementById('myElement')
document.querySelector('#myElement')

上面代碼中,兩個(gè)方法都能選中id為myElement的元素,但是getElementById()比querySelector()效率高得多。

(3)querySelectorAll()

querySelectorAll方法返回匹配指定的CSS選擇器的所有節(jié)點(diǎn),返回的是NodeList類型的對(duì)象。NodeList對(duì)象不是動(dòng)態(tài)集合,所以元素節(jié)點(diǎn)的變化無(wú)法實(shí)時(shí)反映在返回結(jié)果中。

elementList = document.querySelectorAll(selectors);

querySelectorAll方法的參數(shù),可以是逗號(hào)分隔的多個(gè)CSS選擇器,返回所有匹配其中一個(gè)選擇器的元素。

var matches = document.querySelectorAll("div.note, div.alert");

上面代碼返回class屬性是note或alert的div元素。

querySelectorAll方法支持復(fù)雜的CSS選擇器。

// 選中data-foo-bar屬性等于someval的元素
document.querySelectorAll('[data-foo-bar="someval"]');

// 選中myForm表單中所有不通過(guò)驗(yàn)證的元素
document.querySelectorAll('#myForm :invalid');

// 選中div元素,那些class含ignore的除外
document.querySelectorAll('DIV:not(.ignore)');

// 同時(shí)選中div,a,script三類元素
document.querySelectorAll('DIV, A, SCRIPT');

如果querySelectorAll方法和getElementsByTagName方法的參數(shù)是字符串“*”,則會(huì)返回文檔中的所有HTML元素節(jié)點(diǎn)。

與querySelector方法一樣,querySelectorAll方法無(wú)法選中CSS偽元素。

(4)getElementsByClassName()

getElementsByClassName方法返回一個(gè)類似數(shù)組的對(duì)象(HTMLCollection類型的對(duì)象),包括了所有class名字符合指定條件的元素(搜索范圍包括本身),元素的變化實(shí)時(shí)反映在返回結(jié)果中。這個(gè)方法不僅可以在document對(duì)象上調(diào)用,也可以在任何元素節(jié)點(diǎn)上調(diào)用。

// document對(duì)象上調(diào)用
var elements = document.getElementsByClassName(names);
// 非document對(duì)象上調(diào)用
var elements = rootElement.getElementsByClassName(names);

getElementsByClassName方法的參數(shù),可以是多個(gè)空格分隔的class名字,返回同時(shí)具有這些節(jié)點(diǎn)的元素。

document.getElementsByClassName('red test');

上面代碼返回class同時(shí)具有red和test的元素。

(5)getElementsByTagName()

getElementsByTagName方法返回所有指定標(biāo)簽的元素(搜索范圍包括本身)。返回值是一個(gè)HTMLCollection對(duì)象,也就是說(shuō),搜索結(jié)果是一個(gè)動(dòng)態(tài)集合,任何元素的變化都會(huì)實(shí)時(shí)反映在返回的集合中。這個(gè)方法不僅可以在document對(duì)象上調(diào)用,也可以在任何元素節(jié)點(diǎn)上調(diào)用。

var paras = document.getElementsByTagName("p");

上面代碼返回當(dāng)前文檔的所有p元素節(jié)點(diǎn)。

注意,getElementsByTagName方法會(huì)將參數(shù)轉(zhuǎn)為小寫(xiě)后,再進(jìn)行搜索。

(6)getElementsByName()

getElementsByName方法用于選擇擁有name屬性的HTML元素,比如form、img、frame、embed和object,返回一個(gè)NodeList格式的對(duì)象,不會(huì)實(shí)時(shí)反映元素的變化。

// 假定有一個(gè)表單是<form name="x"></form>
var forms = document.getElementsByName("x");
forms[0].tagName // "FORM"

注意,在IE瀏覽器使用這個(gè)方法,會(huì)將沒(méi)有name屬性、但有同名id屬性的元素也返回,所以name和id屬性最好設(shè)為不一樣的值。

(7)elementFromPoint()

elementFromPoint方法返回位于頁(yè)面指定位置的元素。

var element = document.elementFromPoint(x, y);

上面代碼中,elementFromPoint方法的參數(shù)x和y,分別是相對(duì)于當(dāng)前窗口左上角的橫坐標(biāo)和縱坐標(biāo),單位是CSS像素。elementFromPoint方法返回位于這個(gè)位置的DOM元素,如果該元素不可返回(比如文本框的滾動(dòng)條),則返回它的父元素(比如文本框)。如果坐標(biāo)值無(wú)意義(比如負(fù)值),則返回null。

createElement(),createTextNode(),createAttribute(),createDocumentFragment()

以下方法用于生成元素節(jié)點(diǎn)。

(1)createElement()

createElement方法用來(lái)生成HTML元素節(jié)點(diǎn)。

var element = document.createElement(tagName);
// 實(shí)例
var newDiv = document.createElement("div");

createElement方法的參數(shù)為元素的標(biāo)簽名,即元素節(jié)點(diǎn)的tagName屬性。如果傳入大寫(xiě)的標(biāo)簽名,會(huì)被轉(zhuǎn)為小寫(xiě)。如果參數(shù)帶有尖括號(hào)(即)或者是null,會(huì)報(bào)錯(cuò)。

(2)createTextNode()

createTextNode方法用來(lái)生成文本節(jié)點(diǎn),參數(shù)為所要生成的文本節(jié)點(diǎn)的內(nèi)容。

var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.appendChild(newContent);

上面代碼新建一個(gè)div節(jié)點(diǎn)和一個(gè)文本節(jié)點(diǎn),然后將文本節(jié)點(diǎn)插入div節(jié)點(diǎn)。

(3)createAttribute()

createAttribute方法生成一個(gè)新的屬性對(duì)象節(jié)點(diǎn),并返回它。

attribute = document.createAttribute(name);

createAttribute方法的參數(shù)name,是屬性的名稱。

var node = document.getElementById("div1");
var a = document.createAttribute("my_attrib");
a.value = "newVal";
node.setAttributeNode(a);

// 等同于

var node = document.getElementById("div1");
node.setAttribute("my_attrib", "newVal");

(4)createDocumentFragment()

createDocumentFragment方法生成一個(gè)DocumentFragment對(duì)象。

var docFragment = document.createDocumentFragment();

DocumentFragment對(duì)象是一個(gè)存在于內(nèi)存的DOM片段,但是不屬于當(dāng)前文檔,常常用來(lái)生成較復(fù)雜的DOM結(jié)構(gòu),然后插入當(dāng)前文檔。這樣做的好處在于,因?yàn)镈ocumentFragment不屬于當(dāng)前文檔,對(duì)它的任何改動(dòng),都不會(huì)引發(fā)網(wǎng)頁(yè)的重新渲染,比直接修改當(dāng)前文檔的DOM有更好的性能表現(xiàn)。

var docfrag = document.createDocumentFragment();

[1, 2, 3, 4].forEach(function(e) {
  var li = document.createElement("li");
  li.textContent = e;
  docfrag.appendChild(li);
});

document.body.appendChild(docfrag);

createEvent()

createEvent方法生成一個(gè)事件對(duì)象,該對(duì)象可以被element.dispatchEvent方法使用,觸發(fā)指定事件。

var event = document.createEvent(type);

createEvent方法的參數(shù)是事件類型,比如UIEvents、MouseEvents、MutationEvents、HTMLEvents。

var event = document.createEvent('Event');
event.initEvent('build', true, true);
document.addEventListener('build', function (e) {
  // ...
}, false);
document.dispatchEvent(event);

createNodeIterator(),createTreeWalker()

以下方法用于遍歷元素節(jié)點(diǎn)。

(1)createNodeIterator()

createNodeIterator方法返回一個(gè)DOM的子節(jié)點(diǎn)遍歷器。

var nodeIterator = document.createNodeIterator(
  document.body,
  NodeFilter.SHOW_ELEMENT
);

上面代碼返回body元素的遍歷器。createNodeIterator方法的第一個(gè)參數(shù)為遍歷器的根節(jié)點(diǎn),第二個(gè)參數(shù)為所要遍歷的節(jié)點(diǎn)類型,這里指定為元素節(jié)點(diǎn)。其他類型還有所有節(jié)點(diǎn)(NodeFilter.SHOW_ALL)、文本節(jié)點(diǎn)(NodeFilter.SHOW_TEXT)、評(píng)論節(jié)點(diǎn)(NodeFilter.SHOW_COMMENT)等。

所謂“遍歷器”,在這里指可以用nextNode方法和previousNode方法依次遍歷根節(jié)點(diǎn)的所有子節(jié)點(diǎn)。

var nodeIterator = document.createNodeIterator(document.body);
var pars = [];
var currentNode;

while (currentNode = nodeIterator.nextNode()) {
  pars.push(currentNode);
}

上面代碼使用遍歷器的nextNode方法,將根節(jié)點(diǎn)的所有子節(jié)點(diǎn),按照從頭部到尾部的順序,讀入一個(gè)數(shù)組。nextNode方法先返回遍歷器的內(nèi)部指針?biāo)诘墓?jié)點(diǎn),然后會(huì)將指針移向下一個(gè)節(jié)點(diǎn)。所有成員遍歷完成后,返回null。previousNode方法則是先將指針移向上一個(gè)節(jié)點(diǎn),然后返回該節(jié)點(diǎn)。

var nodeIterator = document.createNodeIterator(
  document.body,
  NodeFilter.SHOW_ELEMENT
);

var currentNode = nodeIterator.nextNode();
var previousNode = nodeIterator.previousNode();

currentNode === previousNode // true

上面代碼中,currentNode和previousNode都指向同一個(gè)的節(jié)點(diǎn)。

有一個(gè)需要注意的地方,遍歷器返回的第一個(gè)節(jié)點(diǎn),總是根節(jié)點(diǎn)。

(2)createTreeWalker()

createTreeWalker方法返回一個(gè)DOM的子樹(shù)遍歷器。它與createNodeIterator方法的區(qū)別在于,后者只遍歷子節(jié)點(diǎn),而它遍歷整個(gè)子樹(shù)。

createTreeWalker方法的第一個(gè)參數(shù),是所要遍歷的根節(jié)點(diǎn),第二個(gè)參數(shù)指定所要遍歷的節(jié)點(diǎn)類型。

var treeWalker = document.createTreeWalker(
  document.body,
  NodeFilter.SHOW_ELEMENT
);

var nodeList = [];

while(treeWalker.nextNode()) nodeList.push(treeWalker.currentNode);

上面代碼遍歷body節(jié)點(diǎn)下屬的所有元素節(jié)點(diǎn),將它們插入nodeList數(shù)組。

adoptNode(),importNode()

以下方法用于獲取外部文檔的節(jié)點(diǎn)。

(1)adoptNode()

adoptNode方法將某個(gè)節(jié)點(diǎn),從其原來(lái)所在的文檔移除,插入當(dāng)前文檔,并返回插入后的新節(jié)點(diǎn)。

node = document.adoptNode(externalNode);

importNode方法從外部文檔拷貝指定節(jié)點(diǎn),插入當(dāng)前文檔。

var node = document.importNode(externalNode, deep);

(2)importNode()

importNode方法用于創(chuàng)造一個(gè)外部節(jié)點(diǎn)的拷貝,然后插入當(dāng)前文檔。它的第一個(gè)參數(shù)是外部節(jié)點(diǎn),第二個(gè)參數(shù)是一個(gè)布爾值,表示對(duì)外部節(jié)點(diǎn)是深拷貝還是淺拷貝,默認(rèn)是淺拷貝(false)。雖然第二個(gè)參數(shù)是可選的,但是建議總是保留這個(gè)參數(shù),并設(shè)為true。

另外一個(gè)需要注意的地方是,importNode方法只是拷貝外部節(jié)點(diǎn),這時(shí)該節(jié)點(diǎn)的父節(jié)點(diǎn)是null。下一步還必須將這個(gè)節(jié)點(diǎn)插入當(dāng)前文檔的DOM樹(shù)。

var iframe = document.getElementsByTagName("iframe")[0];
var oldNode = iframe.contentWindow.document.getElementById("myNode");
var newNode = document.importNode(oldNode, true);
document.getElementById("container").appendChild(newNode);

上面代碼從iframe窗口,拷貝一個(gè)指定節(jié)點(diǎn)myNode,插入當(dāng)前文檔。

addEventListener(),removeEventListener(),dispatchEvent()

以下三個(gè)方法與Document節(jié)點(diǎn)的事件相關(guān)。這些方法都繼承自EventTarget接口,詳細(xì)介紹參見(jiàn)《Event對(duì)象》章節(jié)的《EventTarget》部分。

// 添加事件監(jiān)聽(tīng)函數(shù)
document.addEventListener('click', listener, false);

// 移除事件監(jiān)聽(tīng)函數(shù)
document.removeEventListener('click', listener, false);

// 觸發(fā)事件
var event = new Event('click');
document.dispatchEvent(event);
以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)