DOM操作

文檔對象模型 DOM


DOM 是 JavaScript 操作?頁的接口,全稱為“文檔對象模型”(Document Object Model)。它的作用是將?頁轉為一個 JavaScript 對象,從而可以?腳本進行各種操作 (?如增刪內容)。
DOM 的最小組成單位叫做節點(node)。?檔的樹形結構(DOM樹),就是由各種不同類型的節點組成。

DOM樹

節點的類型有七種


瀏覽器提供?個原生的節點對象 Node ,下面這七種節點都繼承了 Node ,因此具有?些共同的屬性和?法。最常用的是document對象和Element對象。

  • Document :整個文檔樹的頂層節點
  • DocumentType : doctype 標簽(?如 <!DOCTYPE html> )
  • Element :?頁的各種HTML標簽(比如 <body> 、 <a> 等)
  • Attribute :?頁元素的屬性(?如 class="right" )
  • Text :標簽之間或標簽包含的?本
  • Comment :注釋
  • DocumentFragment :?檔的?段

document 對象


每個載入瀏覽器的HTML文檔都會成為document對象。document對象表示整個HTML頁面,是window對象的一個屬性。

document對象常用屬性

document.doctype   //獲取HTML文檔的doctype聲明,例如<!DOCTYPE html>,沒有則返回null
document.title  //返回當前文檔的標題,該屬性是可寫的
document.characterSet //返回渲染當前文檔的字符集,例如"UTF-8"
document.head //獲取文檔中被head節點包裹的內容
document.body //獲取文檔中被body節點包裹的內容
document.images //獲取文檔中所有圖片

document.readyState // 返回當前文檔的狀態,共有三種可能的值
//1. loading:加載HTML代碼階段,尚未完成解析
//2. interactive:加載外部資源階段
//3. complete:全部加載完成

document.compatMode 屬性返回瀏覽器處理文檔的模式,共有兩種可能的值
//1. BackCompat:向后兼容模式,也就是沒有添加DOCTYPE
//2. CSS1Compat:嚴格模式,添加了DOCTYPE

document.activeElement //返回當前文檔中獲得焦點的那個元素
//用戶通常可以使用tab鍵移動焦點,使用空格鍵激活焦點

document.location //返回一個只讀對象,提供了當前文檔的URL信息
document.location === location //true
document.location === window.location //true
// 假定當前網址為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"
document.location.assign('http://www.google.com') //跳轉到另一個網址
document.location.reload(true) // 優先從服務器重新加載
document.location.reload(false) // 優先從本地緩存重新加載(默認值)
document.location.assign('http://www.google.com') // 跳轉到另一個網址,但當前文檔不保留在history對象中,即無法用后退按鈕,回到當前文檔
document.location.toString() // 將location對象轉為字符串,等價于document.location.href
//雖然location屬性返回的對象是只讀的,但是可以將指定的URL賦值給這個屬性!網頁就會自動跳轉到指定網址。
document.location = 'http://www.example.com';// 即跳轉至網頁http://www.example.com

document.cookie //獲取該文檔的cookie信息,cookie是存儲在客戶端的文本

document.getElementById('XXX').innerText //返回元素內包含的文本內容,可寫屬性,在多層次的時候會按照元素由淺到深的順序拼接其內容。
<div>
    <p>
        123
        <span>456</span>
    </p>
</div>
外層div的innerText返回內容是 "123456"

document.getElementById('XXX').innerHTML //和inerText類似,但不是返回元素的文本內容,而是返回元素的HTML結構
<div>
    <p>
        123
        <span>456</span>
    </p>
</div>
外層div的innerHTML返回內容是<p>123<span>456</span></p>

document.open(); //新建一個文檔,供write方法寫入內容。它實際上等于清除當前文檔,重新寫入內容
document.write("hello"); //向當前文檔寫入內容
document.write("world"); 
document.close(); //用于關閉open方法所新建的文檔。一旦關閉,write方法就無法寫入內容了
注意:
1.如果頁面已經渲染完成再調用write方法,它會先調用open方法,擦除當前文檔所有內容,然后再寫入。
2.如果在頁面渲染過程中調用write方法,并不會調用open方法。

Element對象


除了document對象,在DOM中最常用的就是Element對象了,Element對象表示HTML元素,提供了對元素標簽名、子節點以及特性的訪問。
Element 對象可以擁有類型為元素節點、文本節點、注釋節點的子節點,DOM提供了一系列的方法可以進行元素的增、刪、改、查操作。

Element對象屬性

nodeName:元素標簽名,還有個類似的tagName
nodeType:元素類型
className:類名
id:元素id
children:子元素列表(HTMLCollection)
childNodes:子元素列表(NodeList)
firstChild:第一個子元素
lastChild:最后一個子元素
nextSibling:下一個兄弟元素
previousSibling:上一個兄弟元素
parentNode、parentElement:父元素

用法舉例:

document.getElementById("MathJax_Message").nodeName  //"DIV"

查詢元素 (querySelector()最佳)

getElementById()
返回匹配指定ID屬性的元素節點。

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

getElementsByClassName()
返回一個類數組的對象,包括了所有class名字符合指定條件的元素

var elements = document.getElementsByClassName(names);
document.getElementsByClassName('red test');

getElementsByClassName方法的參數,可以是多個空格分隔的class名字,返回同時具有這些節點的元素。這個方法不僅可以在document對象上調用,也可以在任何元素節點上調用。

getElementsByTagName()
getElementsByTagName方法返回所有指定標簽的元素(搜索范圍包括本身)。這個方法不僅可以在document對象上調用,也可以在任何元素節點上調用。

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

querySelector()
querySelector方法返回匹配指定的CSS選擇器的元素節點。如果有多個節點滿足匹配條件,則返回第一個匹配的節點。
即通過querySelector()使用css選擇器的方法去操作dom元素,需要注意兼容性,支持IE9及以上,對IE8部分支持

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

注意:querySelector方法無法選中CSS偽元素。

querySelectorAll()
querySelectorAll方法返回匹配指定的CSS選擇器的所有節點,返回的是NodeList類型的對象。NodeList對象不是動態集合,所以元素節點的變化無法實時反映在返回結果中。

elementList = document.querySelectorAll(selectors);

querySelectorAll方法的參數,可以是逗號分隔的多個CSS選擇器,返回所有匹配其中一個選擇器的元素。

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

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

創建元素

createElement(標簽名)
createElement方法用來生成HTML元素節點。

var newDiv = document.createElement("div");

createElement方法的參數為元素的標簽名,即元素節點的tagName屬性。
如果傳入大寫的標簽名,會被轉為小寫。如果參數帶有尖括號(即<和>)或者是null,會報錯。

createTextNode()
createTextNode方法用來生成文本節點,參數為所要生成的文本節點的內容。

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

上面代碼新建一個div節點和一個文本節點

createDocumentFragment()
createDocumentFragment方法生成一個DocumentFragment對象。

var docFragment = document.createDocumentFragment();

DocumentFragment對象是一個存在于內存的DOM片段,但是不屬于當前文檔,常常用來生成較復雜的DOM結構,然后插入當前文檔。這樣做的好處在于,因為DocumentFragment不屬于當前文檔,對它的任何改動,都不會引發網頁的重新渲染,比直接修改當前文檔的DOM有更好的性能表現。

修改元素&刪除元素&clone元素

appendChild()
接受一個節點對象作為參數,將其作為最后一個子節點,插入當前節點。

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

上面代碼將新建的文本節點插入到新建的div節點的尾部。

var p = document.createElement('p');
document.body.appendChild(p);

上面代碼新建一個<p>節點,將其插入document.body的尾部。

如果appendChild方法的參數是DocumentFragment節點,那么插入的是DocumentFragment的所有子節點,而不是DocumentFragment節點本身。返回值是一個空的DocumentFragment節點。

insertBefore()
insertBefore方法用于將某個節點插入父節點內部的指定位置。

var insertedNode = parentNode.insertBefore(newNode, referenceNode);

insertBefore方法接受兩個參數,第一個參數是所要插入的節點newNode,第二個參數是父節點parentNode內部的一個子節點referenceNode。newNode將插在referenceNode這個子節點的前面。返回值是插入的新節點newNode。

var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.insertBefore(newContent, newDiv.firstChild);

newContent將插在newDiv.firstChild的前面

如果insertBefore方法的第二個參數為null,則新節點將插在當前節點內部的最后位置,即變成最后一個子節點。

var newDiv = document.createElement("div");
var newContent = document.createTextNode("Hello");
newDiv.insertBefore(newContent, null);

由于不存在insertAfter方法,如果新節點要插在父節點的某個子節點后面,可以用insertBefore方法結合nextSibling屬性模擬。

parent.insertBefore(s1, s2.nextSibling);

replaceChild()替換指定元素
replaceChild()接受兩個參數:要插入的元素和要替換的元素,返回值是替換走的那個節點oldElement。

newDiv.replaceChild(newElement, oldElement);

removeChild()移除子節點
接受一個子節點作為參數,用于從當前節點移除該子節點。返回值是移除的子節點。

parentNode.removeChild(childNode);

Node.hasChildNodes()判斷是否有子節點
hasChildNodes方法返回一個布爾值,表示當前節點是否有子節點。

var foo = document.getElementById('foo');

if (foo.hasChildNodes()) {
  foo.removeChild(foo.childNodes[0]);
}

上面代碼表示,如果foo節點有子節點,就移除第一個子節點。

cloneNode()克隆一個節點
它接受一個布爾值作為參數,表示是否同時克隆子節點,false的時候只復制元素本身。它的返回值是一個克隆出來的新節點。

var cloneUL = document.querySelector('ul').cloneNode(true);

該方法有一些使用注意點。

  1. 克隆一個節點,會拷貝該節點的所有屬性,但是會喪失addEventListener方法和on-屬性(即node.onclick = fn),添加在這個節點上的事件回調函數。
  2. 該方法返回的節點不在文檔之中,即沒有任何父節點,必須使用諸如Node.appendChild這樣的方法添加到文檔之中。
  3. 克隆一個節點之后,DOM 有可能出現兩個有相同id屬性(即id="xxx")的網頁元素,這時應該修改其中一個元素的id屬性。如果原節點有name屬性,可能也需要修改。

contains()判斷是否包含和這個節點

document.body.contains(node)
返回一個布爾值,表示參數節點是否滿足以下三個條件之一。

  1. 參數節點為當前節點。
  2. 參數節點為當前節點的子節點。
  3. 參數節點為當前節點的后代節點。
document.body.contains(node)

上面代碼檢查參數節點node,是否包含在當前文檔之中。

HTMLCollection 和 NodeList

節點都是單個對象,有時需要一種數據結構,能夠容納多個節點。DOM 提供兩種節點集合,用于容納多個節點:NodeList和HTMLCollection。

NodeList 對象代表一個有順序的節點列表,HTMLCollection 是一個接口,表示 HTML 元素的集合,它提供了可以遍歷列表的方法和屬性。都是類數組對象, NodeList 有 forEach 方法,而 HTMLCollection 沒有。

以下方法獲取HTMLCollection對象實例

document.images //所有img元素
document.links //所有帶href屬性的a元素和area元素
document.forms //所有form元素
document.scripts //所有script元素
document.body.children
document.getElementsByClassName("class1")

以下方法獲取NodeList對象實例

Node.childNodes
document.querySelectorAll()
document.getElementsByTagName()
document.getElementsByName("name1")
document.body.childNodes instanceof NodeList // true

NodeList實例是一個類數組對象,具有length屬性和forEach方法(也可以用for遍歷),可以使用方括號運算符取出成員。但不能使用pop或push之類數組特有的方法。

var children = document.body.childNodes;
Array.isArray(children) // false

children.length // 34
children.forEach(console.log)
document.body.childNodes[0] //返回第一個成員

如果NodeList實例要使用數組方法,可以使用Array.prototype.slice.call()將其轉為真正的數組。

var children = document.body.childNodes;
var nodeArr = Array.prototype.slice.call(children);

注意:NodeList 實例可能是動態集合,也可能是靜態集合。所謂動態集合就是一個活的集合,DOM 刪除或新增一個相關節點,都會立刻反映在 NodeList 實例。目前,只有Node.childNodes返回的是一個動態集合,其他的 NodeList 都是靜態集合。

var children = document.body.childNodes;
children.length // 18
document.body.appendChild(document.createElement('p'));
children.length // 19

上面代碼中,文檔增加一個子節點,NodeList 實例children的length屬性就增加了1。

NodeList.prototype.length

length屬性返回NodeList 實例包含的節點數量。

document.getElementsByTagName('xxx').length

NodeList.prototype.forEach()

forEach方法用于遍歷 NodeList 的所有成員。它接受一個回調函數作為參數,每一輪遍歷就執行一次這個回調函數,用法與數組實例的forEach方法完全一致。

var children = document.body.childNodes;
children.forEach(function(item,i,list){})

回調函數的三個參數依次是當前元素、當前元素索引值、整個NodeList 實例

NodeList.prototype.keys(),NodeList.prototype.values(),NodeList.prototype.entries()

keys()返回鍵名的遍歷器,values()返回鍵值的遍歷器,entries()返回的遍歷器同時包含鍵名和鍵值的信息。都可以通過for...of循環遍歷獲取每一個成員的信息。

var children = document.body.childNodes;

for (var key of children.keys()) {
  console.log(key);
}
// 0
// 1
// 2
// ...

for (var value of children.values()) {
  console.log(value);
}
// #text
// <script>
// ...

for (var entry of children.entries()) {
  console.log(entry);
}
// Array [ 0, #text ]
// Array [ 1, <script> ]
// ...

屬性操作

getAttribute()獲取元素的attribute值(一個標簽的屬性名和屬性值可以自己定義)

var node = document.querySelector('p')
node.getAttribute('id');

setAttribute(屬性名,屬性值) 設置元素屬性

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

romoveAttribute() 刪除元素屬性

node.removeAttribute('id');

常見使用方式

樣式的改變建議使用 class 的新增刪除來實現

Element.classList方法: 操作元素的class

var nodeBox = document.querySelector('.box')
console.log( nodeBox.classList )
nodeBox.classList.add('active')   //新增 class
nodeBox.classList.remove('active')  //刪除 class
nodeBox.classList.toggle('active')   //新增/刪除切換(即如果類存在,則刪除它并返回false,如果不存在,則添加它并返回true。)
node.classList.contains('active')   // 判斷是否存在指定的class
Element.classList.item ( Number ) //按集合中的索引返回class值

頁面寬高

網頁可見區域寬: document.body.clientWidth;
網頁可見區域高: document.body.clientHeight;
網頁可見區域寬: document.body.offsetWidth (包括邊線的寬);
網頁可見區域高: document.body.offsetHeight (包括邊線的寬);


image

image

網頁正文全文寬: document.body.scrollWidth;
網頁正文全文高: document.body.scrollHeight;
網頁被卷去的高: document.body.scrollTop;
網頁被卷去的左: document.body.scrollLeft;
網頁正文部分上: window.screenTop;
網頁正文部分左: window.screenLeft;
屏幕分辨率的高: window.screen.height;
屏幕分辨率的寬: window.screen.width;
屏幕可用工作區高度: window.screen.availHeight;
屏幕可用工作區寬度:window.screen.availWidth;

Element.scrollHeight: 只讀屬性,是一個元素內容高度的度量
Element.scrollTop:獲取或設置一個元素的內容垂直滾動的像素數
scrollWidth:獲取對象的滾動寬度
offsetHeight:獲取對象相對于版面或由父坐標 offsetParent 屬性指定的父坐標的高度
offsetTop:獲取對象相對于版面或由 offsetTop 屬性指定的父坐標的計算頂端位置
event.clientX 相對文檔的水平座標
event.clientY 相對文檔的垂直座標
event.offsetX 相對容器的水平坐標
event.offsetY 相對容器的垂直坐標
event.clientX+document.documentElement.scrollTop 相對文檔的水平座標+垂直方向滾動的量

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,923評論 6 535
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,740評論 3 420
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,856評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,175評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,931評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,321評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,383評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,533評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,082評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,891評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,618評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,319評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,732評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,987評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,794評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,076評論 2 375

推薦閱讀更多精彩內容

  • 基本介紹 文檔對象模型 (DOM) 是HTML和XML文檔的編程接口。它給文檔(結構樹)提供了一個結構化的表述并且...
    草鞋弟閱讀 450評論 0 0
  • 節點 節點類型 每個節點都有一個 nodeType 屬性,用于表示節點類型。nodeType 屬性返回節點的類型。...
    練曉習閱讀 462評論 0 4
  • 什么是DOM??? DOM(Document Object Model 文檔對象模型)是針對HTML和XML文檔的...
    熒惑3_3閱讀 1,404評論 0 1
  • 1、 dom對象的innerText和innerHTML有什么區別? innerText是一個可寫屬性,返回元素內...
    zh_yang閱讀 332評論 0 0
  • #幸福是需要修出來的~每天進步1%~幸福實修11班~學號10#賈雙紅 20170913(17/30) 【幸福三朵】...
    幸福實修賈雙紅閱讀 197評論 3 2