看圖識文(取自 寒冬winter 的微博)。
文章裏引用了MDN
和《javascript
高級程序設計3》裏的知識。
若有不對的地方,敬請指出。
javascript
建立元素:
document.createElement()
css
使用document.createElement()
能夠建立新元素。這個方法只接受一個參數,即要建立元素的標籤名。這個標籤名在HTML
文檔中不區分大小寫,在XHTML
中區分大小寫。html
var div = document.createElement("div");
使用createElement()
方法建立新元素的同時,也爲新元素設置了ownerDocument
屬性,能夠操做元素的特性。前端
div.id = "myDiv"; div.className = "div1";
此時,新元素還沒有被添加到文檔樹中,所以設置各類特性均不會影響瀏覽器的顯示。要添加到文檔樹,可用appendChild()、insertBefore()、replaceChild()
。(稍後講到)html5
document.body.appendChild(div);
當把元素添加到文檔樹中後,伺候鬼這個元素作的任何修改都會實時地反應到瀏覽器中。java
在IE
中能夠爲createElement()
方法傳入完整的元素標籤和屬性。(只在IE
中兼容)node
var div = document.createElement("<div id=\"mydiv\" class=\"div1\"></div>"); 不能再標籤里加其餘元素節點或者文本節點,以下的方式和上面的得出的節點同樣 var div = document.createElement("<div id=\"mydiv\" class=\"div1\">12212</div>");
建立文本節點 :
document.createTextNode
chrome
使用document.createTextNode()
來建立文本節點,這個方法接受一個參數:要插入節點的文本。與設置已有文本節點的值同樣,做爲參數的文本將按照HTML
或XML
的格式進行編碼。瀏覽器
document.createTextNode("121212");
能夠添加多個文本節點。假如兩個文本節點時相鄰的同胞節點,那麼兩個文本節點會連起來,中間不會有空格。app
(IE9
之前不將換行和空格看作文本節點,其餘瀏覽器會)
文本關係以下:
<div id="div1"> <div id="div2">2</div> <div id="div3">3</div> <div id="div4">4</div> </div>
父節點:
parentNode
parentNode
是指定節點的父節點.一個元素節點的父節點多是一個元素(Element
)節點,也多是一個文檔(Document
)節點,或者是個文檔碎片(DocumentFragment
)節點.
每個節點都有一個parentNode
屬性。
對於下面的節點類型: Attr, Document, DocumentFragment, Entity, Notation,其parentNode屬性返回null
。若是當前節點剛剛被創建,尚未被插入到DOM
樹中,則該節點的parentNode
屬性也返回null
。
<script type="text/javascript"> var child2 = document.getElementById("div2"); var parent = child2.parentNode; </script>
子節點:
childNodes
childNodes
返回包含指定節點的子節點的集合,該集合爲即時更新的集合(live collection
)。
即時更新就是對節點元素的任意修改都會當即反映到結果裏。
<script type="text/javascript"> var child2 = document.getElementById("div2"); var parent = child2.parentNode; var allChilds = parent.childNodes; console.log(allChilds.length) // IE下是3,其餘瀏覽器是7 var nodeAdd = document.createElement("div"); var textAdd = document.createTextNode("這是添加的文本節點"); nodeAdd.appendChild(textAdd); parent.appendChild(nodeAdd); console.log(allChilds.length);// IE下是4,其餘瀏覽器是8 </script>
兄弟節點:
nextSibling,previousSibling
nextSibling
返回某節點的下一個兄弟節點,previousSibling
返回某節點的上一個兄弟節點,沒有的話返回null
。
注意:可能由於元素換行的緣由返回的是text
節點。
<script type="text/javascript"> var child3 = document.getElementById("div3"); var next = child3.nextSibling; var previous = child3.previousSibling; console.log(next); // IE下返回div4,其餘返回text console.log(previous) // IE下返回div2,其餘返回text </script>
第一個或最後一個子節點:
firstChild、lastChild
firstChild
返回node
的子節點中的第一個節點的引用,沒有返回null
lastChild
返回node
的子節點中的最後一個節點的引用,沒有返回null
<script type="text/javascript"> var child3 = document.getElementById("div3"); var parent = child3.parentNode; var first = parent.firstChild; // IE是div2,其餘是text var last = parent.lastChild; // IE是div4,其餘是text </script>
只算元素,不算文本節點。
如下三個方法用法和節點關係徹底同樣,只是這三個方法只看元素節點,無論由於空格、換行形成的文本節點或者手動加上去的文本節點。children
: 返回全部元素子節點(IE5+、ff3.五、opera三、chrome
,但在IE8
及如下會將註釋節點當作一個元素節點)
如下兩個IE9+
才支持nextElementSibling
:返回元素的下一個兄弟元素節點previousElementSibling
: 返回元素的上一個兄弟元素節點
appendChild()
appendChild()
用於向childNodes
列表的末尾添加一個節點,而且返回這個新增的節點。
若是傳入到appendChild()
裏的節點已是文檔的一部分了,那結果就是將節點從原來的位置轉移到新位置,任何一個節點不能同時出如今文檔中的多個位置。
var returnNode = someNode.appendChild(someNode.firstChild); // 返回第一個節點 console.log(returnNode === someNode.firstChild); // false console.log(returnNode === someNode.lastChild); // true
insetBefore()
insetBefore()
能夠將節點插入到某個特定的位置。這個方法接受兩個參數:要插入的節點和做爲參照的節點。
插入節點後,被插入的節點變成參照節點的前一個同胞節點,同時被方法返回。 若是參照節點是null
,則與appendChild()
執行相同的操做。
// 插入後成爲最後一個子節點 var returnNode = someNode.insetBefore(newNode, null); console.log(returnNode === someNode.lastChild); // true // 插入後成爲第一個子節點 var returnNode = someNode.insetBefore(newNode, someNode.firstChild); console.log(returnNode === newNode); // true console.log(returnNode === someNode.firstChild); // true // 插入到最後一個子節點的前面 var returnNode = someNode.insetBefore(newNode, someNode.lastChild); console.log(returnNode === someNode.childNodes[someNode.childnodes.length - 2]) // true
替換節點:
replaceChild()
replaceChild()
接受兩個參數:要插入的節點和要被替換的節點。被替換的節點將由這個方法返回並從文檔中被移除,同時由要插入的節點佔據其位置。
// 替換第一個子節點 var returnNode = someNode.replaceChild(newNode, someNode.firstChild);
使用replaceChild()
後,被替換的節點的全部關係指針都會被複制到插入的節點上面。
刪除節點:
removeChild()
該方法移除節點,接受一個參數,即要移除的節點,同時該方法返回被移除的節點。只能是一個節點,不能是一組節點。
// 移除第一個子節點 var returnNode = someNode.removeChild(newNode, someNode.firstChild);
克隆節點:
cloneNode(true/false)
返回調用該方法的節點的一個副本。參數表示是否採用深度克隆,若是爲true
,則該節點的全部後代節點也都會被克隆,若是爲false
,則只克隆該節點自己,文本或者換行、空格這些不會複製,由於他們都是一個textNode
。
注意: 在DOM4
規範中(實現於Gecko 13.0(Firefox 13.0 / Thunderbird 13.0 / SeaMonkey 2.10
) , 查看 bug 698391),deep
是一個可選參數. 若是省略的話, deep
參數的默認值爲true
,也就是說,深度克隆是默認的.若是想使用淺克隆, 你須要將該參數指定爲false
。
在舊版本的瀏覽器中, 你始終須要指定deep
參數。
克隆一個元素節點會拷貝它全部的屬性以及屬性值,固然也就包括了屬性上綁定的事件(好比onclick="alert(1)"
),但不會拷貝那些使用addEventListener()
方法或者node.onclick = fn
這種用JavaScript
動態綁定的事件。
注意:爲了防止一個文檔中出現兩個ID
重複的元素,使用cloneNode()
方法克隆的節點在須要時應該指定另一個與原ID
值不一樣的ID
var div1 = document.getElementById("div1"); var cloneHtml = div1.cloneNode(true); document.body.appendChild(cloneHtml);
HTML代碼示例:
<div id="div1"> <p id="div2" class="one" name="nameone">2</p> <div id="div3">3</div> <div id="div4" name="div2">4</div> </div>
querySelector、querySelectorAll
(IE8
及以上)
Selectors API
經過匹配一組選擇器的方式來爲從DOM
中檢索Element
節點提供一些簡單快捷的方法,這比過去必需要在javascript
代碼中用循環來查找某個你想要的特定元素更快一些。
該規範對於使用Document,DocumentFragment和Element
接口的對象都增了兩種新方法:
querySelector
返回節點子樹內與之相匹配的第一個Element
節點。若是沒有匹配的節點,則返回null
。
querySelectorAll
返回一個包含節點子樹內全部與之相匹配的Element
節點列表,若是沒有相匹配的,則返回一個空節點列表。
注意:由 querySelector()
、querySelectorAll()
返回的節點列表不是動態實時的(非live Collection
)。這和其餘DOM
查詢方法返回動態實時節點列表不同。
選擇器方法接受一個或多個用逗號分隔的選擇器來肯定須要被返回的元素。例如,要選擇文檔中全部CSS
的類(class
)是warning
或者note
的段落(p
)元素,能夠這樣寫:
var special = document.querySelectorAll( "p.warning, p.note" );
也能夠經過ID來查詢,例如:
var el = document.querySelector( "#main, #basic, #exclamation" );
執行上面的代碼後,el
就包含了文檔中元素的ID
是main
,basic
或exclamation
的全部元素中的第一個元素。
querySelector() and querySelectorAll()
裏可使用任何CSS
選擇器,他們都不是live Collection
:
var notLive = document.querySelectorAll("p"); console.log(notLive); document.getElementById("div1").removeChild(document.getElementById("div2")); console.log(notLive); // 上面兩個輸出都是輸出 `p#div2.one`的引用,沒有由於刪除了`p`標籤而使`notLive`的結果發生變化。
getElementById()
返回一個匹配特定 ID
的元素。id
是大小寫敏感的字符串,表明了所要查找的元素的惟一ID
,若是沒有則返回null
。
若是新建一個元素,尚未插入到文檔中,則不能經過該方法獲取到。
var notLive = document.getElementById("div2"); console.log(notLive.innerHTML); document.getElementById("div1").removeChild(document.getElementById("div2")); console.log(notLive.innerHTML); // 上面輸出都是2,說明getElementById()也是**非**live collection
getElementsByTagName()
document.getElementsByTagName()
方法返回一個實時的包含具備給出標籤名的元素們的HTMLCollection
。指定的元素的子樹會被搜索,包括元素本身。返回的 list
是實時的(live collection
),意味着它會隨着DOM
樹的變化自動更新。所以,若是對同一個元素,使用相同的參數,是不須要屢次調用document.getElementsByTagName()
的。
Element.getElementsByTagName()
的搜索被限制爲指定元素的後代而不是document
var live = document.getElementsByTagName("p"); console.log(live[0].innerHTML); document.getElementById("div1").removeChild(document.getElementById("div2")); console.log(live[0].innerHTML); // 第一個輸出2,第二個報錯,由於沒法引用到p標籤
getElementsByName()
該方法返回一個實時的nodelist collection
,包含文檔中全部name
屬性匹配的標籤。這是一個**live collection**
。
注意:在IE
和opera
下,若是某個元素1
的name
和另外一個元素2
的id
重合,且元素2
在元素1
的前面,則getElementsByName
()會取到元素2
。
var live = document.getElementsByName("div2"); console.log(live[0].innerHTML); document.getElementById("div1").removeChild(document.getElementById("div2")); console.log(live[0].innerHTML); // chrome下:所有輸出4 // IE下: 第一個輸出2,第二個報錯。
getElementsByClassName()
該方法返回一個即時更新的(live
) HTMLCollection
,包含了全部擁有指定 class
的子元素。當在 document
對象上調用此方法時,會檢索整個文檔,包括根元素。(IE9
如下不支持)
要匹配多個class
,則className
用空格分開。
getElementsByClassName("class1 class2");
var live = document.getElementsByClassName("one"); console.log(live[0].innerHTML); document.getElementById("div1").removeChild(document.getElementById("div2")); console.log(live[0].innerHTML); // 第一個返回2,第二個報錯
setAttribute()
添加一個新屬性(attribute
)到元素上,或改變元素上已經存在的屬性的值。
當在 HTML
文檔中的 HTML
元素上調用 setAttribute()
方法時,該方法會將其屬性名稱(attribute name
)參數小寫化。
若是指定的屬性已經存在,則其值變爲傳遞的值。若是不存在,則建立指定的屬性。也可指定爲null
。若是設置爲null
,最好使用removeAttribute()
。
var div2 = document.getElementById("div2"); div2.setAttribute("class", "new_class"); div2.setAttribute("id", "new_id");
注意:在IE7
下,修改了元素的class
,若是已有class
,則會出現兩個class
,經過setAttribute()
添加的不生效;若是沒有class
,則添加上class
,但這個添加上去的class
的樣式不會生效。
removeAttribute()
該方法用於移除元素的屬性。
var div2 = document.getElementById("div2"); div2.removeAttribute("class");
注意:IE7
下沒法移除 class
屬性
getAttribute()
該方法返回元素上指定屬性(attribute
)的值。若是指定的屬性不存在,則返回 null
或 ""
(空字符串)(IE5+
都返回null
)。
var div2 = document.getElementById("div2"); var attr = div2.getAttribute("class"); console.log(attr);
注意:IE7
下不能正確返回class
,返回的是null
,其餘正常。
hasAttribute()
hasAttribute()
返回一個布爾值,指示該元素是否包含有指定的屬性(attribute
)。
注意:IE7
不支持該方法。
自定義屬性
data-*
html5
裏有一個data-*
去設置獲取元素的自定義屬性值。
<div id="div1" data-aa="11">
利用div1.dataset
能夠得到一個DOMStringMap
,包含了元素的全部data-*
。
使用div1.dataset.aa
就能夠獲取11
的值。
一樣,經過設置div1.dataset.bb = "22"
就能夠設置一個自定義屬性值。
在不兼容的瀏覽器裏,就使用getAttribute
和setAttribute
var div1 = document.getElementById("div1"); var a = null; if (div1.dataset) { a = div1.dataset.aa; div1.dataset.bb = "222"; } else { a = div1.getAttribute("data-aa"); div1.setAttribute("data-bb", "2222"); } console.log(a);
addEventListener()
addEventListener()
將指定的事件監聽器註冊到目標對象上,當目標對象觸發制定的事件時,指定的回調函數就會觸發。目標對象能夠是 文檔上的元素、 document、 window
或者XMLHttpRequest
(好比onreadystatechange
事件)。
IE8
及如下不支持此方法且只有事件冒泡沒有事件捕獲。IE9
開始支持此方法,也就有了事件捕獲。
var div1 = document.getElementById("div1"); div1.addEventListener("click", listener, false); function listener() { console.log('test'); } var cloneHtml = div1.cloneNode(true); document.body.appendChild(cloneHtml);
第一個參數是事件名,第二個是回調函數,第三個參數爲true
表示捕獲,false
表示冒泡。
var div1 = document.getElementById("div1"); div1.addEventListener("click", listener1, true/fasle); function listener1() { console.log('test1'); } var div2 = document.getElementById("div2"); div2.addEventListener("click", listener2, true/fasle); function listener2() { console.log('test2'); }
有一點要注意的是,當對某一個元素1
既綁定了捕獲事件,又綁定了冒泡事件時:
當這個元素1
並非觸發事件的那個元素2
時,則觸發順序會按照先 捕獲 後 冒泡 的順序觸發;
當這個元素1
就是最底層的觸發事件的元素時,則這個元素沒有捕獲和冒泡的區別,誰先綁定就先觸發誰。
var div2 = document.getElementById("div2"); div2.addEventListener("click", listener2, true); function listener2() { console.log('test2'); } div2.addEventListener("click", listener1, false); function listener1() { console.log('test1'); } // 按綁定順序執行,兩個`addEventLister()`顛倒過來則執行順序也變化 // 若是再對`div1`綁定一個捕獲、一個冒泡,則會先觸發捕獲 再 觸發冒泡,與綁定順序無關
removeEventListener()
與addEventListener()
綁定事件對應的就是移除已綁定的事件。第三個參數的布爾值表明解綁的是捕獲事件仍是冒泡事件。兩個事件互不相關。
var div2 = document.getElementById("div2"); div2.addEventListener("click", listener2, true); function listener2() { console.log('test2'); } div2.removeEventListener("click", listener2, true);
注意:只能經過removeEventListener()
解綁有名字的函數,對於綁定的匿名函數沒法解除綁定。
div2.addEventListener("click", function(){ console.log('test'); console.log(this); }, true); div2.removeEventListener("click", function() { console.log("test"); }, true); div2.onclick = null; // 點擊div2依然打印出test
注意:這裏this
指向觸發事件的元素自身。
attachEvent()、detachEvent()
IE8
及如下使用這兩個方法綁定和解綁事件,固然,IE9+
也支持這個事件。但這個方法綁定的事件默認爲冒泡也只有冒泡。
// 這裏須要在事件前加 on div2.attachEvent("onclick", listener1); function listener1() { console.log('test'); console.log(this); } div2.detachEvent("onclick", listener1);
和addEventListener()
同樣,也不能解綁匿名函數。
注意:這裏this
指向 window
。
阻止默認事件和冒泡
標準事件和IE
事件中的阻止默認事件和冒泡事件也有很大區別。
var div2 = document.getElementById("div2"); if (div2.addEventListener) { div2.addEventListener("click", function(e) { e.preventDefault(); // 阻止默認事件 e.stopPropagation(); // 阻止冒泡 console.log(e.target.innerHTML); }, false); } else { div2.attachEvent("onclick", function() { var e = window.event; e.returnValue = false; // 阻止默認事件 e.cancelBubble = true; // 阻止冒泡 console.log(e.srcElement.innerHTML); }); }
IE8
及如下的event
是綁定在window
上的。(個人IE11
裏,仿真到IE7
、IE8
也能夠取到標準事件裏的 e
對象,估計是升級到IE11
的緣由)。
自定義事件:
createEvent()
createEvent()
用於建立一個新的 event
,然後這個 event
必須調用它的 init()
方法進行初始化。最後就能夠在目標元素上使用dispatchEvent()
調用新建立的event
事件了。
createEvent()
的參數通常有:UIEvents、MouseEvents、MutationEvents、HTMLEvents、Event(s)
等等,分別有對應的init()
方法。HTMLEvents、Event(s)
對應的都是initEvent()
方法。
initEvent(type, bubbles, cancelable)
type
表示自定義的事件類型,bubbles
表示是否冒泡,cancelable
表示是否阻止默認事件。
target.dispatchEvent(ev)
target
就是要觸發自定義事件的DOM
元素
var div1 = document.getElementById("div1"); div1.addEventListener("message", function(){ console.log('test'); }, false); var div2 = document.getElementById("div2"); div2.addEventListener("message", function(e){ console.log(this); console.log(e); }, false); var ev = document.createEvent("Event"); ev.initEvent("message", false, true); // 起泡參數變爲true,div1的事件就會觸發 div2.dispatchEvent(ev);
getComputedStyle()、currentStyle()
當咱們想獲取元素計算後實際呈如今頁面上的各個值,就用這兩個方法。IE8
及如下用currentStyle()
,IE9+
及其餘標準瀏覽器用getComputedStyle()
。
var div2 = document.getElementById("div2"); var result = ""; if (window.getComputedStyle) { result = (window || document.defaultView).getComputedStyle(div2, null)['cssFloat']; } else { result = div2.currentStyle["styleFloat"]; } console.log(result); // document.defaultView返回document對象所關聯的window
這兩個方法在不一樣的瀏覽器裏差距也很大。
好比float
屬性:getComputedStyle
: IE9
以上須要用cssFloat
,其餘標準的用float
currentStyle
: IE8
及如下可用styleFloat
或者float
。
好比height
屬性:
假如未設置height
值,標準瀏覽器裏能計算出高度值,而currentStyle
計算出來是auto
。
上面的例子getComputedStyle
是用鍵值去訪問的,也可用getPropertyValue()
去訪問。(IE8
、IE7
不支持)
result = (window || document.defaultView).getComputedStyle(div2, null).getPropertyValue("float");
getBoundingClientRect()、getClientRects()
getBoundingClientRect
()該方法得到頁面中某個元素的上、右、下、左分別相對瀏覽器視窗的位置。getBoundingClientRect
是DOM
元素到瀏覽器可視範圍的距離(到瀏覽器頂部而不是文檔頂部)。該函數返回一個Object
對象,該對象有6
個屬性:top,lef,right,bottom,width,height
;這裏的top、left
和css
中的理解很類似,width、height
是元素自身的寬高,可是right
,bottom
和css
中的理解有點不同。right
是指元素右邊界距窗口最左邊的距離,bottom
是指元素下邊界距窗口最上面的距離。
getClientRects()
是返回一個ClientRectList
集合。
var div1 = document.getElementById("div1"); var rects1 = div1.getClientRects(); var rects2 = div1.getBoundingClientRect(); console.log(rects1[0].top); console.log(rects2.top);