document
節(jié)點(diǎn)對(duì)象代表整個(gè)文檔,每張網(wǎng)頁(yè)都有自己的document
對(duì)象。window.document
屬性就指向這個(gè)對(duì)象。只要瀏覽器開(kāi)始載入 HTML 文檔,該對(duì)象就存在了,可以直接使用。
document
對(duì)象有不同的辦法可以獲取。
document
或window.document
。iframe
框架里面的網(wǎng)頁(yè),使用iframe
節(jié)點(diǎn)的contentDocument
屬性。XMLHttpRequest
對(duì)象的responseXML
屬性。ownerDocument
屬性。 document
對(duì)象繼承了EventTarget
接口和Node
接口,并且混入(mixin)了ParentNode
接口。這意味著,這些接口的方法都可以在document
對(duì)象上調(diào)用。除此之外,document
對(duì)象還有很多自己的屬性和方法。
以下屬性是指向文檔內(nèi)部的某個(gè)節(jié)點(diǎn)的快捷方式。
(1)document.defaultView
document.defaultView
屬性返回document
對(duì)象所屬的window
對(duì)象。如果當(dāng)前文檔不屬于window
對(duì)象,該屬性返回null
。
document.defaultView === window // true
(2)document.doctype
對(duì)于 HTML 文檔來(lái)說(shuō),document
對(duì)象一般有兩個(gè)子節(jié)點(diǎn)。第一個(gè)子節(jié)點(diǎn)是document.doctype
,指向<DOCTYPE>
節(jié)點(diǎn),即文檔類(lèi)型(Document Type Declaration,簡(jiǎn)寫(xiě)DTD)節(jié)點(diǎn)。HTML 的文檔類(lèi)型節(jié)點(diǎn),一般寫(xiě)成<!DOCTYPE html>
。如果網(wǎng)頁(yè)沒(méi)有聲明 DTD,該屬性返回null
。
var doctype = document.doctype;
doctype // "<!DOCTYPE html>"
doctype.name // "html"
document.firstChild
通常就返回這個(gè)節(jié)點(diǎn)。
(3)document.documentElement
document.documentElement
屬性返回當(dāng)前文檔的根元素節(jié)點(diǎn)(root)。它通常是document
節(jié)點(diǎn)的第二個(gè)子節(jié)點(diǎn),緊跟在document.doctype
節(jié)點(diǎn)后面。HTML網(wǎng)頁(yè)的該屬性,一般是<html>
節(jié)點(diǎn)。
(4)document.body,document.head
document.body
屬性指向<body>
節(jié)點(diǎn),document.head
屬性指向<head>
節(jié)點(diǎn)。
這兩個(gè)屬性總是存在的,如果網(wǎng)頁(yè)源碼里面省略了<head>
或<body>
,瀏覽器會(huì)自動(dòng)創(chuàng)建。另外,這兩個(gè)屬性是可寫(xiě)的,如果改寫(xiě)它們的值,相當(dāng)于移除所有子節(jié)點(diǎn)。
(5)document.scrollingElement
document.scrollingElement
屬性返回文檔的滾動(dòng)元素。也就是說(shuō),當(dāng)文檔整體滾動(dòng)時(shí),到底是哪個(gè)元素在滾動(dòng)。
標(biāo)準(zhǔn)模式下,這個(gè)屬性返回的文檔的根元素document.documentElement
(即<html>
)。兼容(quirk)模式下,返回的是<body>
元素,如果該元素不存在,返回null
。
// 頁(yè)面滾動(dòng)到瀏覽器頂部
document.scrollingElement.scrollTop = 0;
(6)document.activeElement
document.activeElement
屬性返回獲得當(dāng)前焦點(diǎn)(focus)的 DOM 元素。通常,這個(gè)屬性返回的是<input>
、<textarea>
、<select>
等表單元素,如果當(dāng)前沒(méi)有焦點(diǎn)元素,返回<body>
元素或null
。
(7)document.fullscreenElement
document.fullscreenElement
屬性返回當(dāng)前以全屏狀態(tài)展示的 DOM 元素。如果不是全屏狀態(tài),該屬性返回null
。
if (document.fullscreenElement.nodeName == 'VIDEO') {
console.log('全屏播放視頻');
}
上面代碼中,通過(guò)document.fullscreenElement
可以知道<video>
元素有沒(méi)有處在全屏狀態(tài),從而判斷用戶行為。
以下屬性返回一個(gè)HTMLCollection
實(shí)例,表示文檔內(nèi)部特定元素的集合。這些集合都是動(dòng)態(tài)的,原節(jié)點(diǎn)有任何變化,立刻會(huì)反映在集合中。
(1)document.links
document.links
屬性返回當(dāng)前文檔所有設(shè)定了href
屬性的<a>
及<area>
節(jié)點(diǎn)。
// 打印文檔所有的鏈接
var links = document.links;
for(var i = 0; i < links.length; i++) {
console.log(links[i]);
}
(2)document.forms
document.forms
屬性返回所有<form>
表單節(jié)點(diǎn)。
var selectForm = document.forms[0];
上面代碼獲取文檔第一個(gè)表單。
除了使用位置序號(hào),id
屬性和name
屬性也可以用來(lái)引用表單。
/* HTML 代碼如下
<form name="foo" id="bar"></form>
*/
document.forms[0] === document.forms.foo // true
document.forms.bar === document.forms.foo // true
(3)document.images
document.images
屬性返回頁(yè)面所有<img>
圖片節(jié)點(diǎn)。
var imglist = document.images;
for(var i = 0; i < imglist.length; i++) {
if (imglist[i].src === 'banner.gif') {
// ...
}
}
上面代碼在所有img
標(biāo)簽中,尋找某張圖片。
(4)document.embeds,document.plugins
document.embeds
屬性和document.plugins
屬性,都返回所有<embed>
節(jié)點(diǎn)。
(5)document.scripts
document.scripts
屬性返回所有<script>
節(jié)點(diǎn)。
var scripts = document.scripts;
if (scripts.length !== 0 ) {
console.log('當(dāng)前網(wǎng)頁(yè)有腳本');
}
(6)document.styleSheets
document.styleSheets
屬性返回網(wǎng)頁(yè)內(nèi)嵌或引入的 CSS 樣式表集合,詳細(xì)介紹請(qǐng)看《CSS 操作》一章。
(7)小結(jié)
除了document.styleSheets
屬性,以上的其他集合屬性返回的都是HTMLCollection
實(shí)例。document.styleSheets
屬性返回的是StyleSheetList
實(shí)例。
document.links instanceof HTMLCollection // true
document.images instanceof HTMLCollection // true
document.forms instanceof HTMLCollection // true
document.embeds instanceof HTMLCollection // true
document.scripts instanceof HTMLCollection // true
HTMLCollection
實(shí)例是類(lèi)似數(shù)組的對(duì)象,所以上面這些屬性都有length
屬性,都可以使用方括號(hào)運(yùn)算符引用成員。如果成員有id
或name
屬性,還可以用這兩個(gè)屬性的值,在HTMLCollection
實(shí)例上引用到這個(gè)成員。
// HTML 代碼如下
// <form name="myForm">
document.myForm === document.forms.myForm // true
以下屬性返回文檔信息。
(1)document.documentURI,document.URL
document.documentURI
屬性和document.URL
屬性都返回一個(gè)字符串,表示當(dāng)前文檔的網(wǎng)址。不同之處是它們繼承自不同的接口,documentURI
繼承自Document
接口,可用于所有文檔;URL
繼承自HTMLDocument
接口,只能用于 HTML 文檔。
document.URL
// http://www.example.com/about
document.documentURI === document.URL
// true
如果文檔的錨點(diǎn)(#anchor
)變化,這兩個(gè)屬性都會(huì)跟著變化。
(2)document.domain
document.domain
屬性返回當(dāng)前文檔的域名,不包含協(xié)議和端口。比如,網(wǎng)頁(yè)的網(wǎng)址是http://www.example.com:80/hello.html
,那么document.domain
屬性就等于www.example.com
。如果無(wú)法獲取域名,該屬性返回null
。
document.domain
基本上是一個(gè)只讀屬性,只有一種情況除外。次級(jí)域名的網(wǎng)頁(yè),可以把document.domain
設(shè)為對(duì)應(yīng)的上級(jí)域名。比如,當(dāng)前域名是a.sub.example.com
,則document.domain
屬性可以設(shè)置為sub.example.com
,也可以設(shè)為example.com
。修改后,document.domain
相同的兩個(gè)網(wǎng)頁(yè),可以讀取對(duì)方的資源,比如設(shè)置的
Cookie。
另外,設(shè)置document.domain
會(huì)導(dǎo)致端口被改成null
。因此,如果通過(guò)設(shè)置document.domain
來(lái)進(jìn)行通信,雙方網(wǎng)頁(yè)都必須設(shè)置這個(gè)值,才能保證端口相同。
(3)document.location
Location
對(duì)象是瀏覽器提供的原生對(duì)象,提供 URL 相關(guān)的信息和操作方法。通過(guò)window.location
和document.location
屬性,可以拿到這個(gè)對(duì)象。
關(guān)于這個(gè)對(duì)象的詳細(xì)介紹,請(qǐng)看《瀏覽器模型》部分的《Location 對(duì)象》章節(jié)。
(4)document.lastModified
document.lastModified
屬性返回一個(gè)字符串,表示當(dāng)前文檔最后修改的時(shí)間。不同瀏覽器的返回值,日期格式是不一樣的。
document.lastModified
// "03/07/2018 11:18:27"
注意,document.lastModified
屬性的值是字符串,所以不能直接用來(lái)比較。Date.parse
方法將其轉(zhuǎn)為Date
實(shí)例,才能比較兩個(gè)網(wǎng)頁(yè)。
var lastVisitedDate = Date.parse('01/01/2018');
if (Date.parse(document.lastModified) > lastVisitedDate) {
console.log('網(wǎng)頁(yè)已經(jīng)變更');
}
如果頁(yè)面上有 JavaScript 生成的內(nèi)容,document.lastModified
屬性返回的總是當(dāng)前時(shí)間。
(5)document.title
document.title
屬性返回當(dāng)前文檔的標(biāo)題。默認(rèn)情況下,返回<title>
節(jié)點(diǎn)的值。但是該屬性是可寫(xiě)的,一旦被修改,就返回修改后的值。
document.title = '新標(biāo)題';
document.title // "新標(biāo)題"
(6)document.characterSet
document.characterSet
屬性返回當(dāng)前文檔的編碼,比如UTF-8
、ISO-8859-1
等等。
(7)document.referrer
document.referrer
屬性返回一個(gè)字符串,表示當(dāng)前文檔的訪問(wèn)者來(lái)自哪里。
document.referrer
// "https://example.com/path"
如果無(wú)法獲取來(lái)源,或者用戶直接鍵入網(wǎng)址而不是從其他網(wǎng)頁(yè)點(diǎn)擊進(jìn)入,document.referrer
返回一個(gè)空字符串。
document.referrer
的值,總是與 HTTP 頭信息的Referer
字段保持一致。但是,document.referrer
的拼寫(xiě)有兩個(gè)r
,而頭信息的Referer
字段只有一個(gè)r
。
(8)document.dir
document.dir
返回一個(gè)字符串,表示文字方向。它只有兩個(gè)可能的值:rtl
表示文字從右到左,阿拉伯文是這種方式;ltr
表示文字從左到右,包括英語(yǔ)和漢語(yǔ)在內(nèi)的大多數(shù)文字采用這種方式。
(9)document.compatMode
compatMode
屬性返回瀏覽器處理文檔的模式,可能的值為BackCompat
(向后兼容模式)和CSS1Compat
(嚴(yán)格模式)。
一般來(lái)說(shuō),如果網(wǎng)頁(yè)代碼的第一行設(shè)置了明確的DOCTYPE
(比如<!doctype html>
),document.compatMode
的值都為CSS1Compat
。
(1)document.hidden
document.hidden
屬性返回一個(gè)布爾值,表示當(dāng)前頁(yè)面是否可見(jiàn)。如果窗口最小化、瀏覽器切換了 Tab,都會(huì)導(dǎo)致導(dǎo)致頁(yè)面不可見(jiàn),使得document.hidden
返回true
。
這個(gè)屬性是 Page Visibility API 引入的,一般都是配合這個(gè) API 使用。
(2)document.visibilityState
document.visibilityState
返回文檔的可見(jiàn)狀態(tài)。
它的值有四種可能。
visible
:頁(yè)面可見(jiàn)。注意,頁(yè)面可能是部分可見(jiàn),即不是焦點(diǎn)窗口,前面被其他窗口部分擋住了。hidden
:頁(yè)面不可見(jiàn),有可能窗口最小化,或者瀏覽器切換到了另一個(gè) Tab。prerender
:頁(yè)面處于正在渲染狀態(tài),對(duì)于用戶來(lái)說(shuō),該頁(yè)面不可見(jiàn)。unloaded
:頁(yè)面從內(nèi)存里面卸載了。
這個(gè)屬性可以用在頁(yè)面加載時(shí),防止加載某些資源;或者頁(yè)面不可見(jiàn)時(shí),停掉一些頁(yè)面功能。
(3)document.readyState
document.readyState
屬性返回當(dāng)前文檔的狀態(tài),共有三種可能的值。
loading
:加載 HTML 代碼階段(尚未完成解析)interactive
:加載外部資源階段complete
:加載完成這個(gè)屬性變化的過(guò)程如下。
document.readyState
屬性等于loading
。<script>
元素,并且沒(méi)有async
或defer
屬性,就暫停解析,開(kāi)始執(zhí)行腳本,這時(shí)document.readyState
屬性還是等于loading
。document.readyState
屬性變成interactive
。document.readyState
屬性變成complete
。下面的代碼用來(lái)檢查網(wǎng)頁(yè)是否加載成功。
// 基本檢查
if (document.readyState === 'complete') {
// ...
}
// 輪詢檢查
var interval = setInterval(function() {
if (document.readyState === 'complete') {
clearInterval(interval);
// ...
}
}, 100);
另外,每次狀態(tài)變化都會(huì)觸發(fā)一個(gè)readystatechange
事件。
document.cookie
屬性用來(lái)操作瀏覽器 Cookie,詳見(jiàn)《瀏覽器模型》部分的《Cookie》章節(jié)。
document.designMode
屬性控制當(dāng)前文檔是否可編輯。該屬性只有兩個(gè)值on
和off
,默認(rèn)值為off
。一旦設(shè)為on
,用戶就可以編輯整個(gè)文檔的內(nèi)容。
下面代碼打開(kāi)iframe
元素內(nèi)部文檔的designMode
屬性,就能將其變?yōu)橐粋€(gè)所見(jiàn)即所得的編輯器。
// HTML 代碼如下
// <iframe id="editor" src="about:blank"></iframe>
var editor = document.getElementById('editor');
editor.contentDocument.designMode = 'on';
document.currentScript
屬性只用在<script>
元素的內(nèi)嵌腳本或加載的外部腳本之中,返回當(dāng)前腳本所在的那個(gè) DOM 節(jié)點(diǎn),即<script>
元素的 DOM 節(jié)點(diǎn)。
<script id="foo">
console.log(
document.currentScript === document.getElementById('foo')
); // true
</script>
上面代碼中,document.currentScript
就是<script>
元素節(jié)點(diǎn)。
document.implementation
屬性返回一個(gè)DOMImplementation
對(duì)象。該對(duì)象有三個(gè)方法,主要用于創(chuàng)建獨(dú)立于當(dāng)前文檔的新的 Document 對(duì)象。
DOMImplementation.createDocument()
:創(chuàng)建一個(gè) XML 文檔。DOMImplementation.createHTMLDocument()
:創(chuàng)建一個(gè) HTML 文檔。DOMImplementation.createDocumentType()
:創(chuàng)建一個(gè) DocumentType 對(duì)象。下面是創(chuàng)建 HTML 文檔的例子。
var doc = document.implementation.createHTMLDocument('Title');
var p = doc.createElement('p');
p.innerHTML = 'hello world';
doc.body.appendChild(p);
document.replaceChild(
doc.documentElement,
document.documentElement
);
上面代碼中,第一步生成一個(gè)新的 HTML 文檔doc
,然后用它的根元素document.documentElement
替換掉document.documentElement
。這會(huì)使得當(dāng)前文檔的內(nèi)容全部消失,變成hello world
。
document.open
方法清除當(dāng)前文檔所有內(nèi)容,使得文檔處于可寫(xiě)狀態(tài),供document.write
方法寫(xiě)入內(nèi)容。
document.close
方法用來(lái)關(guān)閉document.open()
打開(kāi)的文檔。
document.open();
document.write('hello world');
document.close();
document.write
方法用于向當(dāng)前文檔寫(xiě)入內(nèi)容。
在網(wǎng)頁(yè)的首次渲染階段,只要頁(yè)面沒(méi)有關(guān)閉寫(xiě)入(即沒(méi)有執(zhí)行document.close()
),document.write
寫(xiě)入的內(nèi)容就會(huì)追加在已有內(nèi)容的后面。
// 頁(yè)面顯示“helloworld”
document.open();
document.write('hello');
document.write('world');
document.close();
注意,document.write
會(huì)當(dāng)作 HTML 代碼解析,不會(huì)轉(zhuǎn)義。
document.write('<p>hello world</p>');
上面代碼中,document.write
會(huì)將<p>
當(dāng)作 HTML 標(biāo)簽解釋。
如果頁(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ì)自動(dòng)調(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
。
document.write
是 JavaScript 語(yǔ)言標(biāo)準(zhǔn)化之前就存在的方法,現(xiàn)在完全有更符合標(biāo)準(zhǔn)的方法向文檔寫(xiě)入內(nèi)容(比如對(duì)innerHTML
屬性賦值)。所以,除了某些特殊情況,應(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í)不起作用,即在網(wǎng)頁(yè)上顯示不出換行。網(wǎng)頁(yè)上的換行,必須顯式寫(xiě)入<br>
。
document.querySelector
方法接受一個(gè) CSS 選擇器作為參數(shù),返回匹配該選擇器的元素節(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]');
document.querySelectorAll
方法與querySelector
用法類(lèi)似,區(qū)別是返回一個(gè)NodeList
對(duì)象,包含所有匹配給定選擇器的節(jié)點(diǎn)。
elementList = document.querySelectorAll('.myclass');
這兩個(gè)方法的參數(shù),可以是逗號(hào)分隔的多個(gè) CSS 選擇器,返回匹配其中一個(gè)選擇器的元素節(jié)點(diǎn),這與 CSS 選擇器的規(guī)則是一致的。
var matches = document.querySelectorAll('div.note, div.alert');
上面代碼返回class
屬性是note
或alert
的div
元素。
這兩個(gè)方法都支持復(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 三類(lèi)元素
document.querySelectorAll('DIV, A, SCRIPT');
但是,它們不支持 CSS 偽元素的選擇器(比如:first-line
和:first-letter
)和偽類(lèi)的選擇器(比如:link
和:visited
),即無(wú)法選中偽元素和偽類(lèi)。
如果querySelectorAll
方法的參數(shù)是字符串*
,則會(huì)返回文檔中的所有元素節(jié)點(diǎn)。另外,querySelectorAll
的返回結(jié)果不是動(dòng)態(tài)集合,不會(huì)實(shí)時(shí)反映元素節(jié)點(diǎn)的變化。
最后,這兩個(gè)方法除了定義在document
對(duì)象上,還定義在元素節(jié)點(diǎn)上,即在元素節(jié)點(diǎn)上也可以調(diào)用。
document.getElementsByTagName()
方法搜索 HTML 標(biāo)簽名,返回符合條件的元素。它的返回值是一個(gè)類(lèi)似數(shù)組對(duì)象(HTMLCollection
實(shí)例),可以實(shí)時(shí)反映 HTML 文檔的變化。如果沒(méi)有任何匹配的元素,就返回一個(gè)空集。
var paras = document.getElementsByTagName('p');
paras instanceof HTMLCollection // true
上面代碼返回當(dāng)前文檔的所有p
元素節(jié)點(diǎn)。
HTML 標(biāo)簽名是大小寫(xiě)不敏感的,因此getElementsByTagName()
方法的參數(shù)也是大小寫(xiě)不敏感的。另外,返回結(jié)果中,各個(gè)成員的順序就是它們?cè)谖臋n中出現(xiàn)的順序。
如果傳入*
,就可以返回文檔中所有 HTML 元素。
var allElements = document.getElementsByTagName('*');
注意,元素節(jié)點(diǎn)本身也定義了getElementsByTagName
方法,返回該元素的后代元素中符合條件的元素。也就是說(shuō),這個(gè)方法不僅可以在document
對(duì)象上調(diào)用,也可以在任何元素節(jié)點(diǎn)上調(diào)用。
var firstPara = document.getElementsByTagName('p')[0];
var spans = firstPara.getElementsByTagName('span');
上面代碼選中第一個(gè)p
元素內(nèi)部的所有span
元素。
document.getElementsByClassName()
方法返回一個(gè)類(lèi)似數(shù)組的對(duì)象(HTMLCollection
實(shí)例),包括了所有class
名字符合指定條件的元素,元素的變化實(shí)時(shí)反映在返回結(jié)果中。
var elements = document.getElementsByClassName(names);
由于class
是保留字,所以 JavaScript 一律使用className
表示 CSS 的class
。
參數(shù)可以是多個(gè)class
,它們之間使用空格分隔。
var elements = document.getElementsByClassName('foo bar');
上面代碼返回同時(shí)具有foo
和bar
兩個(gè)class
的元素,foo
和bar
的順序不重要。
注意,正常模式下,CSS 的class
是大小寫(xiě)敏感的。(quirks mode
下,大小寫(xiě)不敏感。)
與getElementsByTagName()
方法一樣,getElementsByClassName()
方法不僅可以在document
對(duì)象上調(diào)用,也可以在任何元素節(jié)點(diǎn)上調(diào)用。
// 非document對(duì)象上調(diào)用
var elements = rootElement.getElementsByClassName(names);
document.getElementsByName()
方法用于選擇擁有name
屬性的 HTML 元素(比如<form>
、<radio>
、<img>
、<frame>
、<embed>
和<object>
等),返回一個(gè)類(lèi)似數(shù)組的的對(duì)象(NodeList
實(shí)例),因?yàn)?code>name屬性相同的元素可能不止一個(gè)。
// 表單為 <form name="x"></form>
var forms = document.getElementsByName('x');
forms[0].tagName // "FORM"
document.getElementById()
方法返回匹配指定id
屬性的元素節(jié)點(diǎn)。如果沒(méi)有發(fā)現(xiàn)匹配的節(jié)點(diǎn),則返回null
。
var elem = document.getElementById('para1');
注意,該方法的參數(shù)是大小寫(xiě)敏感的。比如,如果某個(gè)節(jié)點(diǎn)的id
屬性是main
,那么document.getElementById('Main')
將返回null
。
document.getElementById()
方法與document.querySelector()
方法都能獲取元素節(jié)點(diǎn),不同之處是document.querySelector()
方法的參數(shù)使用 CSS 選擇器語(yǔ)法,document.getElementById()
方法的參數(shù)是元素的id
屬性。
document.getElementById('myElement')
document.querySelector('#myElement')
上面代碼中,兩個(gè)方法都能選中id
為myElement
的元素,但是document.getElementById()
比document.querySelector()
效率高得多。
另外,這個(gè)方法只能在document
對(duì)象上使用,不能在其他元素節(jié)點(diǎn)上使用。
document.elementFromPoint()
方法返回位于頁(yè)面指定位置最上層的元素節(jié)點(diǎn)。
var element = document.elementFromPoint(50, 50);
上面代碼選中在(50, 50)
這個(gè)坐標(biāo)位置的最上層的那個(gè) HTML 元素。
elementFromPoint
方法的兩個(gè)參數(shù),依次是相對(duì)于當(dāng)前視口左上角的橫坐標(biāo)和縱坐標(biāo),單位是像素。如果位于該位置的 HTML 元素不可返回(比如文本框的滾動(dòng)條),則返回它的父元素(比如文本框)。如果坐標(biāo)值無(wú)意義(比如負(fù)值或超過(guò)視口大小),則返回null
。
document.elementsFromPoint()
返回一個(gè)數(shù)組,成員是位于指定坐標(biāo)(相對(duì)于視口)的所有元素。
var elements = document.elementsFromPoint(x, y);
document.createElement
方法用來(lái)生成元素節(jié)點(diǎn),并返回該節(jié)點(diǎn)。
var newDiv = document.createElement('div');
createElement
方法的參數(shù)為元素的標(biāo)簽名,即元素節(jié)點(diǎn)的tagName
屬性,對(duì)于 HTML 網(wǎng)頁(yè)大小寫(xiě)不敏感,即參數(shù)為div
或DIV
返回的是同一種節(jié)點(diǎn)。如果參數(shù)里面包含尖括號(hào)(即<
和>
)會(huì)報(bào)錯(cuò)。
document.createElement('<div>');
// DOMException: The tag name provided ('<div>') is not a valid name
注意,document.createElement
的參數(shù)可以是自定義的標(biāo)簽名。
document.createElement('foo');
document.createTextNode
方法用來(lái)生成文本節(jié)點(diǎn)(Text
實(shí)例),并返回該節(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)。
這個(gè)方法可以確保返回的節(jié)點(diǎn),被瀏覽器當(dāng)作文本渲染,而不是當(dāng)作 HTML 代碼渲染。因此,可以用來(lái)展示用戶的輸入,避免 XSS 攻擊。
var div = document.createElement('div');
div.appendChild(document.createTextNode('<span>Foo & bar</span>'));
console.log(div.innerHTML)
// <span>Foo & bar</span>
上面代碼中,createTextNode
方法對(duì)大于號(hào)和小于號(hào)進(jìn)行轉(zhuǎn)義,從而保證即使用戶輸入的內(nèi)容包含惡意代碼,也能正確顯示。
需要注意的是,該方法不對(duì)單引號(hào)和雙引號(hào)轉(zhuǎn)義,所以不能用來(lái)對(duì) HTML 屬性賦值。
function escapeHtml(str) {
var div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
};
var userWebsite = '" onmouseover="alert(\'derp\')" "';
var profileLink = '<a href="' + escapeHtml(userWebsite) + '">Bob</a>';
var div = document.getElementById('target');
div.innerHTML = profileLink;
// <a href="" onmouseover="alert('derp')" "">Bob</a>
上面代碼中,由于createTextNode
方法不轉(zhuǎn)義雙引號(hào),導(dǎo)致onmouseover
方法被注入了代碼。
document.createAttribute
方法生成一個(gè)新的屬性節(jié)點(diǎn)(Attr
實(shí)例),并返回它。
var attribute = document.createAttribute(name);
document.createAttribute
方法的參數(shù)name
,是屬性的名稱。
var node = document.getElementById('div1');
var a = document.createAttribute('my_attrib');
a.value = 'newVal';
node.setAttributeNode(a);
// 或者
node.setAttribute('my_attrib', 'newVal');
上面代碼為div1
節(jié)點(diǎn),插入一個(gè)值為newVal
的my_attrib
屬性。
document.createComment
方法生成一個(gè)新的注釋節(jié)點(diǎn),并返回該節(jié)點(diǎn)。
var CommentNode = document.createComment(data);
document.createComment
方法的參數(shù)是一個(gè)字符串,會(huì)成為注釋節(jié)點(diǎn)的內(nèi)容。
document.createDocumentFragment
方法生成一個(gè)空的文檔片段對(duì)象(DocumentFragment
實(shí)例)。
var docFragment = document.createDocumentFragment();
DocumentFragment
是一個(gè)存在于內(nèi)存的 DOM 片段,不屬于當(dāng)前文檔,常常用來(lái)生成一段較復(fù)雜的 DOM 結(jié)構(gòu),然后再插入當(dāng)前文檔。這樣做的好處在于,因?yàn)?code>DocumentFragment不屬于當(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);
});
var element = document.getElementById('ul');
element.appendChild(docfrag);
上面代碼中,文檔片斷docfrag
包含四個(gè)<li>
節(jié)點(diǎn),這些子節(jié)點(diǎn)被一次性插入了當(dāng)前文檔。
document.createEvent
方法生成一個(gè)事件對(duì)象(Event
實(shí)例),該對(duì)象可以被element.dispatchEvent
方法使用,觸發(fā)指定事件。
var event = document.createEvent(type);
document.createEvent
方法的參數(shù)是事件類(lèi)型,比如UIEvents
、MouseEvents
、MutationEvents
、HTMLEvents
。
var event = document.createEvent('Event');
event.initEvent('build', true, true);
document.addEventListener('build', function (e) {
console.log(e.type); // "build"
}, false);
document.dispatchEvent(event);
上面代碼新建了一個(gè)名為build
的事件實(shí)例,然后觸發(fā)該事件。
這三個(gè)方法用于處理document
節(jié)點(diǎn)的事件。它們都繼承自EventTarget
接口,詳細(xì)介紹參見(jiàn)《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);
document.hasFocus
方法返回一個(gè)布爾值,表示當(dāng)前文檔之中是否有元素被激活或獲得焦點(diǎn)。
var focused = document.hasFocus();
注意,有焦點(diǎn)的文檔必定被激活(active),反之不成立,激活的文檔未必有焦點(diǎn)。比如,用戶點(diǎn)擊按鈕,從當(dāng)前窗口跳出一個(gè)新窗口,該新窗口就是激活的,但是不擁有焦點(diǎn)。
document.adoptNode
方法將某個(gè)節(jié)點(diǎn)及其子節(jié)點(diǎn),從原來(lái)所在的文檔或DocumentFragment
里面移除,歸屬當(dāng)前document
對(duì)象,返回插入后的新節(jié)點(diǎn)。插入的節(jié)點(diǎn)對(duì)象的ownerDocument
屬性,會(huì)變成當(dāng)前的document
對(duì)象,而parentNode
屬性是null
。
var node = document.adoptNode(externalNode);
document.appendChild(node);
注意,document.adoptNode
方法只是改變了節(jié)點(diǎn)的歸屬,并沒(méi)有將這個(gè)節(jié)點(diǎn)插入新的文檔樹(shù)。所以,還要再用appendChild
方法或insertBefore
方法,將新節(jié)點(diǎn)插入當(dāng)前文檔樹(shù)。
document.importNode
方法則是從原來(lái)所在的文檔或DocumentFragment
里面,拷貝某個(gè)節(jié)點(diǎn)及其子節(jié)點(diǎn),讓它們歸屬當(dāng)前document
對(duì)象。拷貝的節(jié)點(diǎn)對(duì)象的ownerDocument
屬性,會(huì)變成當(dāng)前的document
對(duì)象,而parentNode
屬性是null
。
var node = document.importNode(externalNode, deep);
document.importNode
方法的第一個(gè)參數(shù)是外部節(jié)點(diǎn),第二個(gè)參數(shù)是一個(gè)布爾值,表示對(duì)外部節(jié)點(diǎn)是深拷貝還是淺拷貝,默認(rèn)是淺拷貝(false)。雖然第二個(gè)參數(shù)是可選的,但是建議總是保留這個(gè)參數(shù),并設(shè)為true
。
注意,document.importNode
方法只是拷貝外部節(jié)點(diǎn),這時(shí)該節(jié)點(diǎn)的父節(jié)點(diǎn)是null
。下一步還必須將這個(gè)節(jié)點(diǎn)插入當(dāng)前文檔樹(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)前文檔。
document.createNodeIterator
方法返回一個(gè)子節(jié)點(diǎn)遍歷器。
var nodeIterator = document.createNodeIterator(
document.body,
NodeFilter.SHOW_ELEMENT
);
上面代碼返回<body>
元素子節(jié)點(diǎn)的遍歷器。
document.createNodeIterator
方法第一個(gè)參數(shù)為所要遍歷的根節(jié)點(diǎn),第二個(gè)參數(shù)為所要遍歷的節(jié)點(diǎn)類(lèi)型,這里指定為元素節(jié)點(diǎn)(NodeFilter.SHOW_ELEMENT
)。幾種主要的節(jié)點(diǎn)類(lèi)型寫(xiě)法如下。
document.createNodeIterator
方法返回一個(gè)“遍歷器”對(duì)象(NodeFilter
實(shí)例)。該實(shí)例的nextNode()
方法和previousNode()
方法,可以用來(lái)遍歷所有子節(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è)節(jié)點(diǎn),總是根節(jié)點(diǎn)。
pars[0] === document.body // true
document.createTreeWalker
方法返回一個(gè) DOM 的子樹(shù)遍歷器。它與document.createNodeIterator
方法基本是類(lèi)似的,區(qū)別在于它返回的是TreeWalker
實(shí)例,后者返回的是NodeIterator
實(shí)例。另外,它的第一個(gè)節(jié)點(diǎn)不是根節(jié)點(diǎn)。
document.createTreeWalker
方法的第一個(gè)參數(shù)是所要遍歷的根節(jié)點(diǎn),第二個(gè)參數(shù)指定所要遍歷的節(jié)點(diǎn)類(lèi)型(與document.createNodeIterator
方法的第二個(gè)參數(shù)相同)。
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ù)組。
(1)document.execCommand()
如果document.designMode
屬性設(shè)為on
,那么整個(gè)文檔用戶可編輯;如果元素的contenteditable
屬性設(shè)為true
,那么該元素可編輯。這兩種情況下,可以使用document.execCommand()
方法,改變內(nèi)容的樣式,比如document.execCommand('bold')
會(huì)使得字體加粗。
document.execCommand(command, showDefaultUI, input)
該方法接受三個(gè)參數(shù)。
command
:字符串,表示所要實(shí)施的樣式。showDefaultUI
:布爾值,表示是否要使用默認(rèn)的用戶界面,建議總是設(shè)為false
。input
:字符串,表示該樣式的輔助內(nèi)容,比如生成超級(jí)鏈接時(shí),這個(gè)參數(shù)就是所要鏈接的網(wǎng)址。如果第二個(gè)參數(shù)設(shè)為true
,那么瀏覽器會(huì)彈出提示框,要求用戶在提示框輸入該參數(shù)。但是,不是所有瀏覽器都支持這樣做,為了兼容性,還是需要自己部署獲取這個(gè)參數(shù)的方式。var url = window.prompt('請(qǐng)輸入網(wǎng)址');
if (url) {
document.execCommand('createlink', false, url);
}
上面代碼中,先提示用戶輸入所要鏈接的網(wǎng)址,然后手動(dòng)生成超級(jí)鏈接。注意,第二個(gè)參數(shù)是false
,表示此時(shí)不需要自動(dòng)彈出提示框。
document.execCommand()
的返回值是一個(gè)布爾值。如果為false
,表示這個(gè)方法無(wú)法生效。
這個(gè)方法大部分情況下,只對(duì)選中的內(nèi)容生效。如果有多個(gè)內(nèi)容可編輯區(qū)域,那么只對(duì)當(dāng)前焦點(diǎn)所在的元素生效。
document.execCommand()
方法可以執(zhí)行的樣式改變有很多種,下面是其中的一些:bold、insertLineBreak、selectAll、createLink、insertOrderedList、subscript、delete、insertUnorderedList、superscript、formatBlock、insertParagraph、undo、forwardDelete、insertText、unlink、insertImage、italic、unselect、insertHTML、redo。這些值都可以用作第一個(gè)參數(shù),它們的含義不難從字面上看出來(lái)。
(2)document.queryCommandSupported()
document.queryCommandSupported()
方法返回一個(gè)布爾值,表示瀏覽器是否支持document.execCommand()
的某個(gè)命令。
if (document.queryCommandSupported('SelectAll')) {
console.log('瀏覽器支持選中可編輯區(qū)域的所有內(nèi)容');
}
(3)document.queryCommandEnabled()
document.queryCommandEnabled()
方法返回一個(gè)布爾值,表示當(dāng)前是否可用document.execCommand()
的某個(gè)命令。比如,bold
(加粗)命令只有存在文本選中時(shí)才可用,如果沒(méi)有選中文本,就不可用。
// HTML 代碼為
// <input type="button" value="Copy" onclick="doCopy()">
function doCopy(){
// 瀏覽器是否支持 copy 命令(選中內(nèi)容復(fù)制到剪貼板)
if (document.queryCommandSupported('copy')) {
copyText('你好');
}else{
console.log('瀏覽器不支持');
}
}
function copyText(text) {
var input = document.createElement('textarea');
document.body.appendChild(input);
input.value = text;
input.focus();
input.select();
// 當(dāng)前是否有選中文字
if (document.queryCommandEnabled('copy')) {
var success = document.execCommand('copy');
input.remove();
console.log('Copy Ok');
} else {
console.log('queryCommandEnabled is false');
}
}
上面代碼中,先判斷瀏覽器是否支持copy
命令(允許可編輯區(qū)域的選中內(nèi)容,復(fù)制到剪貼板),如果支持,就新建一個(gè)臨時(shí)文本框,里面寫(xiě)入內(nèi)容“你好”,并將其選中。然后,判斷是否選中成功,如果成功,就將“你好”復(fù)制到剪貼板,再刪除那個(gè)臨時(shí)文本框。
這個(gè)方法指向window.getSelection()
,參見(jiàn)window
對(duì)象一節(jié)的介紹。
更多建議: