原生DOM入門

原生DOM接口挺多的,須要花點時間研究下,不過先把基礎整好,後面框架估計好學點。javascript

1. DOM是啥

1.1 知識回顧

先回顧一下HTML的基本結構html

<!DOCTYPE html>
<html lang="zh-Hans">
<head>
</head>
<body>
</body>
</html>
複製代碼

以上就是最簡單的HTML 5的結構。通常咱們會把它處理成一棵樹,一棵節點樹。java

樹結構

以上就是一棵樹,瀏覽器把html渲染成的樹,也就是Document結構。每一個框就是一個Element、標題等文本內容是Text。node


Document、Element、Text 的祖先都是Node。 如下是MDN的繼承樹編程

但是在內存中,存的不是html樹,是一棵對應html各個節點的對象樹,並且對象樹的節點是與html樹的節點一一對應的。數組

對象樹

以上是內存中的對象樹。這些對象應該怎麼定義,是由DOM規範規定的。瀏覽器

也能夠以下這麼理解bash

Js基本語法的對應

頁面中的節點,根據Element、Text、Document、Comment這些構造函數,構造出對象來,內存就理解了。app

好比構造div框架

var div = document.createElement('div')
undefined
div 
<div></div> //打印結果
複製代碼

createElement就是構造函數。

把DOM的對應和JS基本語法練習起來。

1.2 DOM的真面目

前面的基礎分析完了,就能夠知道什麼是DOM了。

完整的DOM

DOM就是完整的把Document和Object映射到一塊兒,符合DOM規範的結構,因此具有不少的API。

DOM 是 JavaScript 操做網頁的接口,全稱爲「文檔對象模型」(Document Object Model)。它的做用是將網頁轉爲一個 JavaScript 對象,從而能夠用腳本進行各類操做(好比增刪內容)。

瀏覽器會根據 DOM 模型,將結構化文檔(好比 HTML 和 XML)解析成一系列的節點,再由這些節點組成一個樹狀結構(DOM Tree)。全部的節點和最終的樹狀結構,都有規範的對外接口。因此,DOM 能夠理解成網頁的編程接口。DOM 有本身的國際標準,目前的通用版本是DOM 3,下一代版本DOM 4正在擬定中。

嚴格地說,DOM 不屬於 JavaScript,可是操做 DOM 是 JavaScript 最多見的任務,而 JavaScript 也是最經常使用於 DOM 操做的語言。


規範裏的DOM模型居然有多達31個接口,我先只挑Node接口和Document接口學習。


2. 原生DOM API

DOM是一棵樹,樹上有Node,Node分爲Document、Element、Text,其餘的能夠忽略。

由前面的繼承圖可知Node的研究價值很高,咱們先來看Node接口的屬性和方法。 下面是MDN對Node接口的解釋

Node是一個接口,許多DOM類型從這個接口繼承,並容許相似地處理(或測試)這些各類類型。

  • 如下接口都從Node繼承其方法和屬性: Document, Element, CharacterData (which Text, Comment, and CDATASection inherit), ProcessingInstruction, DocumentFragment, DocumentType, Notation, Entity, EntityReference

2.1 Node的屬性

DOM樹的最小單位就是節點(node)。文檔的樹形結構就是有各個不一樣列類型的節點組成的,每一個節點均可以看作是這棵DOM樹的葉子

常見的七種node類型

名字 做用
Document 整個文檔樹的頂層節點 但不是根節點
DocumentType doctype標籤
Element 網頁的其餘各類標籤
Attribute 標籤的屬性
Text 標籤與標籤之間的文本
Comment 註釋
DocumentFragment 文檔的片斷

咱們只關心Document、Element、Text

2.1.1 node之間的關係屬性

  1. 一個最頂層的節點 document,表明整個文檔。
  2. 一個根節點 html,是文檔裏面最高的一層,是根節點。其餘全部的html標籤都是他的下級
  3. 其餘節點與周圍節點的關係
    1. parentNode: 直接的那個上級的節點
    2. childNodes: 直接的下一級的節點
    3. sibling:擁有同一個父節點的節點
Node.childNodes

返回一個NodeList集合,成員包括當前節點的全部子節點。注意,除了HTML元素節點,該屬性返回的還包括Text節點和Comment節點。若是當前節點不包括任何子節點,則返回一個空的NodeList集合。因爲NodeList對象是一個動態集合,一旦子節點發生變化,馬上會反映在返回結果之中。

  • childNodes

注意: childNodes會把text也打印出來,也就是兩個標籤之間的換行符。

文本節點

並且childNodes返回一個僞數組。這個僞數組對象的每個元素依然都是html元素,若是想操做元素的內容還要用元素的其餘屬性。

  • document的childNodes只有兩個
document.childNodes
(2) [<!DOCTYPE html>, html] 0:<!DOCTYPE html> 1:html length:2 __proto__: NodeList 複製代碼
  • 因此咱們不想打印出text節點,可使用children屬性啊
ParentNode.children //ParentNode要是一個HTMLCollection
複製代碼

上述children屬性會返回 一個Node的子elements 而沒有text節點。

Node.firstChild和Node.lastChild

firstChild屬性返回當前節點的第一個子節點,若是當前節點沒有子節點,則返回null(注意,不是undefined)。

Node.lastChild屬性返回當前節點的最後一個子節點,若是當前節點沒有子節點,則返回null。

Node.nextSibling和Node.previousSibling

Node.nextSibling屬性返回緊跟在當前節點後面的第一個同級節點。若是當前節點後面沒有同級節點,則返回null

previousSibling屬性返回當前節點前面的、距離最近的一個同級節點。若是當前節點前面沒有同級節點,則返回null

以上的三組屬性使用時必定要注意結果會有text的影響。

Node.parentNode
document.parentNode
null
複製代碼

parentNode屬性返回當前節點的父節點。對於一個節點來講,它的父節點只多是三種類型:element節點、document節點和documentfragment節點。

並且document節點和documentfragment節點,它們的父節點都是null。另外,對於那些生成後還沒插入DOM樹的節點,父節點也是null。

Node.parentElement

parentElement屬性返回當前節點的父Element節點。若是當前節點沒有父節點,或者父節點類型不是Element節點,則返回null。

注意: 在IE瀏覽器中,只有Element節點纔有該屬性,其餘瀏覽器則是全部類型的節點都有該屬性。

ownerDocument屬性返回當前節點所在的頂層文檔對象,即document對象


2.1.2 node自身的屬性

nodeName和nodeType

nodeName返回node的名字,若是是element那名字是大寫的,其餘的名字前面寫上#。nodeType返回node的類型,通常用數字表示,1表示element(也能夠用Node.ELEMENT_NODE來表示),3表示text(Node.TEXT_NODE)。

  • 若是是element,那麼nodeName === tagName
  • 若是是text,那麼nodeName = #text, tagName = undefined

nodeName和tagName

關於nodeType有個詳細的表格,應該查看MDN記住。對照表

nodeValue

nodeValue屬性返回或設置當前節點的值。對於text, comment節點來講, nodeValue返回該節點的文本內容,對於 attribute 節點來講, 返回該屬性的屬性值,而對於document和element節點來講,返回null。 貌似沒個卵用,最多見的element都是null,仍是用下面的textContent

textContent和innerText之爭

火狐推出的textContent,得到一個節點及其後代的文本內容,通常用這個得到元素的內容。

IE推出的innerText,二者有很大的區別。

關於textContent、innerText、innnerHTML之間的區別請看MDN


2.2 Node的方法

Node.appendChild()

Node.appendChild() 方法將一個節點添加到指定父節點的子節點列表的末尾

var child = node.appendChild(child);

  • node 是要插入子節點的父節點.
  • child便是參數又是這個方法的返回值.

div添加空的p元素

打印出p那個元素

Node.cloneNode()

這個方法就是克隆一個node,分爲淺拷貝和深拷貝。

  • 淺拷貝,Node.cloneNode()只克隆元素節點自己,而不會克隆它的子節點。包括它的文本節點
  • 深拷貝,Node.cloneNode(true)克隆元素的全部屬性以及子節點

注意:爲了防止一個文檔中出現兩個ID重複的元素,使用cloneNode()方法克隆的節點在須要時應該指定另一個與原ID值不一樣的ID

若是你想克隆同一個id的元素到不一樣的元素後面,會報錯。

Node.contains()

判斷一個節點是否是另外一個節點的子節點。

div.contains(div1)
複製代碼

div1是div的子節點就返回true。

Node.hasChildNodes()
div.hasChildNodes()
複製代碼

判斷div節點是否還有子節點,有子節點就返回true。

Node.insertBefore()

在當前節點的某個子節點以前再插入一個子節點。

var insertedElement = parentElement.insertBefore(newElement, referenceElement);
複製代碼

在parentElement節點的子節點referenceElement前面插入一個newElement節點。

若是referenceElementnullnewElement將被插入到子節點的末尾*。*若是newElement已經在DOM樹中,newElement首先會從DOM樹中移除。

沒有 insertAfter 方法。可使用 insertBefore 方法和 nextSibling 來模擬它。

parentDiv.insertBefore(sp1, sp2.nextSibling);
複製代碼

只要sp2.nextSibling === null,那麼就能夠在parentDiv的末尾添加sp1元素。

Node.isEqualNode()和Node.isSameNode()

二者都是比較兩個node是否相等。不過isEqualNode()是兩個node看起來相等就返回true,isSameNode()嚴格使用===判斷,並且該方法已被廢棄,若是要嚴格判斷兩個node是否指向同一個對象,直接用node1 === node2。

Node.normalize()

就是規範化的意思。什麼是規範化,在一個"規範化"後的DOM樹中,不存在一個空的文本節點,或者兩個相鄰的文本節點。

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

wrapper.appendChild(document.createTextNode("Part 1 "));
wrapper.appendChild(document.createTextNode("Part 2 "));

// 這時(規範化以前),wrapper.childNodes.length === 2
// wrapper.childNodes[0].textContent === "Part 1 "
// wrapper.childNodes[1].textContent === "Part 2 "

wrapper.normalize();
// 如今(規範化以後), wrapper.childNodes.length === 1
// wrapper.childNodes[0].textContent === "Part 1 Part 2"
複製代碼

以上是MDN的例子,很好懂。

未規範化的時候

規範化後

以上是本身模仿的demo

Node.removeChild()和Node.replaceChild()

Node.removeChild()是從當前節點刪除一個子節點,不過內存裏面依然存在,只不過不在頁面顯示了,返回的就是被移除的那個節點。因此說一個節點移除之後,依然可使用它,好比插入到另外一個節點下面。

未移除子元素的時候

移除以後

以上是我作的demo

Node.replaceChild方法用於將一個新的節點,替換掉當前節點的一個子節點。它接受兩個參數,第一個參數是用來替換的新節點,第二個參數將要被替換走的子節點。它返回被替換走的那個節點。

未替換

替換了

我作的實驗demo

Document屬性和方法

關於Document接口的屬性和方法,且聽下回分解~

相關文章
相關標籤/搜索