(九)JavaScript DOM操作詳解
DOM (Document Object Model)
DOM定義了表示和修改文件所需方法。DOM物件即為宿主物件,由瀏覽器廠商定義,用來操作html
和xml
功能的一類物件的集合。
節點(node)
DOM 的最小組成單位叫做節點(node)。文件的樹形結構(DOM 樹),就是由各種不同型別的節點組成。每個節點可以看作是文件樹的一片葉子。
節點的型別有七種。
- Document:整個文件樹的頂層節點
- DocumentType:doctype標籤(比如
<!DOCTYPE html>
) - Element:網頁的各種HTML標籤(比如
<body>
、<a>
等) - Attribute:網頁元素的屬性(比如
class="right"
- Text:標籤之間或標籤包含的文字
- Comment:註釋
- DocumentFragment:文件的片段
瀏覽器提供一個原生的節點物件Node,上面這七種節點都繼承了Node,因此具有一些共同的屬性和方法。
節點(node)的一些屬性
Node.prototype.nodeType
nodeType
屬性返回一個整數值,表示節點的型別。
- 文件節點(document):9
- 文件型別節點(DocumentType):10
- 元素節點(element):1
- 屬性節點(attr):2
- 文字節點(text):3
- 註釋節點(Comment):8
- 文件片斷節點(DocumentFragment):11
Node.prototype.nodeName
nodeName
Node.prototype.nodeValue
nodeValue
屬性返回當前節點本身的文字值,該屬性可讀寫。 只有文字節點(text)和註釋節點(comment)有文字值
遍歷節點
Node.prototype.parentNode
parentNode
屬性返回當前節點的父節點
Node.prototype.childNodes
childNodes
屬性返回當前節點的所有子節點
。
Node.prototype.firstChild,Node.prototype.lastChild
firstChild
屬性返回第一個子節點
,lastChild
屬性返回最後一個子節點
Node.prototype.previousSibling,Node.prototype.nextSibling
previousSibling
前一個兄弟節點
,nextSibling
屬性返回後一個兄弟節點
遍歷元素節點
Node.prototype.parentElement
parentElement
屬性返回當前節點的父元素節點
。 (IE9以下不相容)
ParentNode.children / Element.children
children
屬性返回當前節點的所有子元素節點
。
ParentNode.firstElementChild,ParentNode.lastElementChild / Element.firstElementChild,Element.lastElementChild
firstElementChild
屬性返回當前節點的第一個子元素節點
。 (IE9以下不相容)
lastElementChild
屬性返回當前節點的最後一個子元素節點
。 (IE9以下不相容)
Element.nextElementSibling,Element.previousElementSibling
nextElementSibling
返回前一個兄弟元素節點 (IE9以下不相容)
previousElementSibling
返回後一個兄弟元素節點 (IE9以下不相容)
節點(node)的一些方法
Node.prototype.hasChildNodes()
hasChildNodes
方法返回一個布林值,表示當前節點是否有子節點。
插入節點
Node.prototype.appendChild()
appendChild
方法接受一個節點物件作為引數,將其作為最後一個子節點,插入當前節點。該方法的返回值就是插入文件的子節點。
如果引數節點是 DOM 已經存在的節點,appendChild方法會將其從原來的位置,移動到新位置。
//新建一個 <p> 節點,將其插入document.body的尾部
var p = document.createElement('p');
document.body.appendChild(p);
Node.prototype.insertBefore()
var insertedNode = parentNode.insertBefore(newNode, referenceNode);
insertBefore
方法接受兩個引數,第一個引數是所要插入的節點newNode,第二個引數是父節點parentNode內部的一個子節點referenceNode。newNode將插在referenceNode這個子節點的前面。返回值是插入的新節點newNode。
var p = document.createElement('p');
document.body.insertBefore(p, document.body.firstChild);
上面程式碼中,新建一個<p>
節點,插在document.body.firstChild的前面,也就是成為document.body的第一個子節點。
注意,如果所要插入的節點是當前 DOM 現有的節點,則該節點將從原有的位置移除,插入新的位置。
append()、prepend()、before()、after() 這些新的方法存在相容性問題。
ParentNode.append(),ParentNode.prepend()
append
方法為當前節點追加一個或多個子節點,位置是最後一個元素子節點的後面。
該方法不僅可以新增元素子節點,還可以新增文字子節點。
var parent = document.body;
// 新增元素子節點
var p = document.createElement('p');
parent.append(p);
// 新增文字子節點
parent.append('Hello');
// 新增多個元素子節點
var p1 = document.createElement('p');
var p2 = document.createElement('p');
parent.append(p1, p2);
// 新增元素子節點和文字子節點
var p = document.createElement('p');
parent.append('Hello', p);
注意,該方法沒有返回值。
prepend
方法為當前節點追加一個或多個子節點,位置是第一個元素子節點的前面。它的用法與append方法完全一致,也是沒有返回值。
ChildNode.before(),ChildNode.after()
before
方法用於在當前節點的前面,插入一個或多個同級節點。兩者擁有相同的父節點。
注意,該方法不僅可以插入元素節點,還可以插入文字節點。
var div = document.getElementById('myDiv');
var p = document.createElement('p');
var span = document.createElement('span');
// 插入元素節點
div.before(p);
// 插入文字節點
div.before('Hello');
// 插入多個元素節點
div.before(p, span);
// 插入元素節點和文字節點
div.before(p, 'Hello');
after
方法用於在當前節點的後面,插入一個或多個同級節點,兩者擁有相同的父節點。用法與before方法完全相同。
刪除節點
Node.prototype.removeChild()
removeChild
方法接受一個子節點作為引數,用於從當前節點移除該子節點。返回值是移除的子節點。如果引數節點不是當前節點的子節點,removeChild方法將報錯。
var divA = document.getElementById('A');
divA.parentNode.removeChild(divA);
ChildNode.remove()
remove
方法,移除當前節點
var p = document.getElementsByTagName('p')[0];
p.remove();
document 節點
document
物件繼承了EventTarget
介面、Node
介面、ParentNode
介面。這意味著,這些介面的方法都可以在document物件上呼叫。除此之外,document物件還有很多自己的屬性和方法。
document 節點的一些屬性
document.doctype
屬性,指向<DOCTYPE>
節點,即文件型別(Document Type Declaration,簡寫DTD)節點。HTML 的文件型別節點,一般寫成<!DOCTYPE html>
。如果網頁沒有宣告 DTD,該屬性返回null
。
document.documentElement
屬性返回當前文件的根元素節點(root)。HTML網頁的該屬性,一般是<html>
節點。
document.body,document.head
document.body屬性指向<body>
節點,document.head屬性指向<head>
節點。
document 節點的一些方法
document 獲取 節點的一些方法
document.getElementById()
方法返回匹配指定id
的元素節點。如果沒有發現匹配的節點,則返回null。
document.getElementsByTagName()
方法返回匹配標籤名
的元素節點。返回的是類陣列物件
。(最常用)
document.getElementsByClassName()
方法返回匹配class屬性
的元素節點,引數可是多個class屬性。返回的是類陣列物件
。(IE8及以下IE版本沒有)
document.getElementsByName()
方法返回匹配name屬性
的元素節點。返回的是類陣列物件
(舊版本瀏覽器只有部分標籤生效比如表單、img、iframe)
document.querySelector()
,document.querySelectorAll()
document.querySelector方法接受一個 CSS 選擇器
作為引數,返回一個匹配該選擇器的元素節點。document.querySelectorAll方法可返回多個匹配的元素節點,返回的是類陣列物件
。(IE7及以下IE版本沒有,缺陷:不是實時資料)
document 建立 節點的一些方法
document.createElement
方法用來生成元素節點,並返回該節點。
createElement 方法的引數為元素的標籤名,即元素節點的tagName屬性
var newDiv = document.createElement('div');
document.createTextNode
方法用來生成文字節點(Text例項),並返回該節點。createTextNode方法的引數是文字節點的內容。
//新建一個div節點和一個文字節點,然後將文字節點插入div節點
var newDiv = document.createElement('div');
var newContent = document.createTextNode('Hello');
newDiv.appendChild(newContent);
document.createAttribute
方法生成一個新的屬性節點(Attr例項),並返回它。createAttribute方法的引數name,是屬性的名稱。
//為div1節點,插入一個值為 newVal 的 my_attrib 屬性。
var node = document.getElementById('div1');
var a = document.createAttribute('my_attrib');
a.value = 'newVal';
node.setAttributeNode(a);
// 或者直接
node.setAttribute('my_attrib', 'newVal');
Element (元素節點)
Element 元素節點的一些屬性
Element.innerHTML
Element.innerHTML
屬性返回一個字串,等同於該元素包含的所有 HTML 程式碼。該屬性可讀寫,常用來設定某個節點的內容。
el.innerHTML = '';
如果將innerHTML屬性設為空,等於刪除所有它包含的所有節點。
注意,讀取屬性值的時候,如果文字節點包含&、小於號(<)和大於號(>),innerHTML屬性會將它們轉為實體形式&
、<
、>
。
Element.innerText
(曾經老版本火狐不相容,現在可忽略)
Element.textContent(IE8及以下IE版本不相容)
Element.className,Element.classList
className
屬性用來讀寫當前元素節點的class屬性。它的值是一個字串,每個class之間用空格分割。
classList
屬性返回一個類似陣列的物件,當前元素節點的每個class就是這個物件的一個成員。
// HTML 程式碼 <div class="one two three" id="myDiv"></div>
var div = document.getElementById('myDiv');
div.className
// "one two three"
div.classList
// {
// 0 : "one"
// 1 : "two"
// 2 : "three"
// length : 3
// value : "one two three"
// }
classList
物件有下列方法。
add():增加一個 class。
remove():移除一個 class。
toggle():將某個 class 移入或移出當前元素。
contains():檢查當前元素是否包含某個 class。
item():返回指定索引位置的 class。
toString():將 class 的列表轉為字串。
//html 程式碼為 <div id="myDiv"></div>
var div = document.getElementById('myDiv');
div.classList.add('myClass');
div.classList.add('foo', 'bar');
div.classList.remove('myClass');
div.classList.toggle('myClass'); // 如果 myCssClass 不存在就加入,否則移除
div.classList.contains('myClass'); // 返回 true 或者 false
//html 程式碼變為 <div id="myDiv" class="foo bar myClass"></div>
Element 元素節點的一些方法
Element.getAttribute()
Element.getAttribute
方法返回當前元素節點的指定屬性的值。如果指定屬性不存在,則返回null。
//html 程式碼為 <div class="div-1" data-foo="bar"></div>
var div = document.getElementsByTagName('div')[0];
console.log(div.getAttribute('class')); //div-1
console.log(div.getAttribute('data-foo')); //bar
console.log(div.getAttribute('id')); //null
Element.setAttribute()
Element.setAttribute
方法用於為當前元素節點新增屬性。如果同名屬性已存在,則相當於編輯已存在的屬性。該方法沒有返回值。
//html 程式碼為 <div></div>
var div = document.getElementsByTagName('div')[0];
div.setAttribute('id','demo');
//html 程式碼變為 <div id="demo"></div>
Node結構樹,繼承關係的一些問題
獲取元素節點函式的一些注意點
- getElementById方法定義在Document.prototype上,即Element節點上不能使用。
- getElementsByName方法定義在HTMLDocument.prototype上,即非html中的document(如xml中的document、Element節點)不能使用。
- getElementsByTagName方法定義在Document.prototype和Element.prototype上,即HTML、xml中的document和Element節點都能使用,所以
getElementsByTagName
比較常用。 - getElementsByClassName、querySelector、querySelectorAll在Document.prototype和Element.prototype類中均有定義。