JavaScript DOM操作及擴(kuò)展

什么是DOM?胶坠?骇陈?

DOM(Document Object Model? 文檔對(duì)象模型)是針對(duì)HTML和XML文檔的一個(gè)API(應(yīng)用程序編程接口)革半。

注意,IE中的所有DOM對(duì)象都是以COM(組件對(duì)象模型)對(duì)象的形式實(shí)現(xiàn)的萧朝。IE中的DOM對(duì)象與原生JavaScript對(duì)象的行為或活動(dòng)特點(diǎn)并不一致。

COM對(duì)象是遵循COM規(guī)范編寫、以Win32動(dòng)態(tài)鏈接庫(DLL)或可執(zhí)行文件(EXE)形式發(fā)布的可執(zhí)行二進(jìn)制代碼掷伙,能夠滿足對(duì)組件架構(gòu)的所有需求。DOM定義了一個(gè)Node接口又兵,這個(gè)接口在JavaScript中是作為Node類型實(shí)現(xiàn)的任柜,而在IE8-瀏覽器中的所有DOM對(duì)象都是以COM對(duì)象的形式實(shí)現(xiàn)的。所以沛厨,IE8-瀏覽器并不支持Node對(duì)象的寫法宙地。

1.節(jié)點(diǎn)層次

首先,大家知道 “在Java的世界里逆皮,一切皆對(duì)象“宅粥,同樣,Js 也是电谣。但是秽梅,JavaScript并不具備傳統(tǒng)的面向?qū)ο笳Z言所支持的類和接口等基本結(jié)構(gòu)。DOM描繪了一個(gè)層次化的節(jié)點(diǎn)樹剿牺,允許開發(fā)人員添加企垦、移除和修改頁面的某一部分。

DOM可以將任何HTML或XML文檔描繪成一個(gè)由多層節(jié)點(diǎn)構(gòu)成的結(jié)構(gòu)晒来。節(jié)點(diǎn)分為幾種不同的類型钞诡,每種類型分別表示文檔中不同的信息及(或)標(biāo)記。每個(gè)節(jié)點(diǎn)都擁有各自的特點(diǎn)湃崩、數(shù)據(jù)和方法荧降,另外也與其他節(jié)點(diǎn)存在某種關(guān)系。節(jié)點(diǎn)之間的關(guān)系構(gòu)成了層次攒读,而所有頁面標(biāo)記則表現(xiàn)為一個(gè)一特定節(jié)點(diǎn)為根結(jié)點(diǎn)的樹形結(jié)構(gòu)誊抛。

以HTML為例:

文檔節(jié)點(diǎn)是每個(gè)文檔的根結(jié)點(diǎn)。在這個(gè)例子中整陌,文檔節(jié)點(diǎn)只有一個(gè)子節(jié)點(diǎn)拗窃,即<html>元素瞎领,我們稱之為文檔元素。

文檔元素是文檔的最外元素随夸,文檔中的其他所有元素都包含在文檔元素中九默。每個(gè)文檔只能有一個(gè)文檔元素。在HTML頁面中宾毒,文檔元素始終都是<html>元素驼修。

每一段 標(biāo)記都可以通過樹中的一個(gè)節(jié)點(diǎn)來表示:HTML元素通過元素節(jié)點(diǎn)表示,特性通過特性節(jié)點(diǎn)表示诈铛,文檔類型通過文檔類型節(jié)點(diǎn)表示乙各,而注釋則通過注釋節(jié)點(diǎn)表示。



每個(gè)方框是文檔的節(jié)點(diǎn)幢竹,它表示一個(gè)Node對(duì)象耳峦。樹形的根部Document節(jié)點(diǎn),它代表整個(gè)文檔焕毫。

2.節(jié)點(diǎn)類型

元素節(jié)點(diǎn)? ? ? ? ? ?    ? ? ? ? ?Node.ELEMENT_NODE(1)

屬性節(jié)點(diǎn)? ? ? ? ? ?    ? ? ? ? ?Node.ATTRIBUTE_NODE(2)

文本節(jié)點(diǎn)? ? ? ? ? ?    ? ? ? ? ?Node.TEXT_NODE(3)

CDATA節(jié)點(diǎn) ? ? ? ? ? ? ? ? ? ? ? ? Node.CDATA_SECTION_NODE(4)

實(shí)體引用名稱節(jié)點(diǎn)? ?    ? ?Node.ENTRY_REFERENCE_NODE(5)

實(shí)體名稱節(jié)點(diǎn)? ? ? ?    ? ? ? Node.ENTITY_NODE(6)

處理指令節(jié)點(diǎn)? ? ? ?    ? ? ? Node.PROCESSING_INSTRUCTION_NODE(7)

注釋節(jié)點(diǎn)? ? ? ? ? ?   ? ? ? ? ? ? ?Node.COMMENT_NODE(8)

文檔節(jié)點(diǎn)? ? ? ? ? ?   ? ? ? ? ? ? ?Node.DOCUMENT_NODE(9)

文檔類型節(jié)點(diǎn)? ? ? ?    ? ? ? Node.DOCUMENT_TYPE_NODE(10)

文檔片段節(jié)點(diǎn)? ? ? ?    ? ? ? Node.DOCUMENT_FRAGMENT_NODE(11)

DTD聲明節(jié)點(diǎn) ? ? ? ? ? ? ? ? ? ? ?Node.NOTATION_NODE(12)

Document

Document表示文檔蹲坷,在瀏覽器中,document對(duì)象是HTMLDocument的一個(gè)實(shí)例邑飒,表示整個(gè)頁面循签,它同時(shí)也是window對(duì)象的一個(gè)屬性。Document有下面的特性:

(1)nodeType為9

(2)nodeName為#document

(3)nodeValue為null

(4)parentNode為null

(5)子節(jié)點(diǎn)可能是一個(gè)DocumentType或Element

Element

Element提供了對(duì)元素標(biāo)簽名疙咸,子節(jié)點(diǎn)和特性的訪問县匠,我們常用HTML元素比如div,span撒轮,a等標(biāo)簽就是element中的一種聚唐。

Element有下面幾條特性:

(1)nodeType為1

(2)nodeName為元素標(biāo)簽名,tagName也是返回標(biāo)簽名

(3)nodeValue為null

(4)parentNode可能是Document或Element

(5)子節(jié)點(diǎn)可能是Element腔召,Text杆查,Comment,Processing_Instruction臀蛛,CDATASection或EntityReference

Text

Text表示文本節(jié)點(diǎn)亲桦,它包含的是純文本內(nèi)容,不能包含html代碼浊仆,但可以包含轉(zhuǎn)義后的html代碼客峭。Text有下面的特性:

(1)nodeType為3

(2)nodeName為#text

(3)nodeValue為文本內(nèi)容

(4)parentNode是一個(gè)Element

(5)沒有子節(jié)點(diǎn)

Attr

Attr類型表示元素的特性,相當(dāng)于元素的attributes屬性中的節(jié)點(diǎn)抡柿,它有下面的特性:

(1)nodeType值為2

(2)nodeName是特性的名稱

(3)nodeValue是特性的值

(4)parentNode為null

Comment

Comment表示HTML文檔中的注釋舔琅,它有下面的幾種特征:

(1)nodeType為8

(2)nodeName為#comment

(3)nodeValue為注釋的內(nèi)容

(4)parentNode可能是Document或Element

(5)沒有子節(jié)點(diǎn)

DocumentFragment類型

DocumentFragment是所有節(jié)點(diǎn)中唯一一個(gè)沒有對(duì)應(yīng)標(biāo)記的類型,它表示一種輕量級(jí)的文檔洲劣,可能當(dāng)作一個(gè)臨時(shí)的倉(cāng)庫用來保存可能會(huì)添加到文檔中的節(jié)點(diǎn)备蚓。DocumentFragment有下面的特性:

(1)nodeType為11

(2)nodeName為#document-fragment

(3)nodeValue為null

(4)parentNode為null

節(jié)點(diǎn)創(chuàng)建型

createElement

createElement通過傳入指定的一個(gè)標(biāo)簽名來創(chuàng)建一個(gè)元素课蔬,如果傳入的標(biāo)簽名是一個(gè)未知的,則會(huì)創(chuàng)建一個(gè)自定義的標(biāo)簽郊尝,注意:IE8以下瀏覽器不支持自定義標(biāo)簽二跋。

使用如下:

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

使用createElement要注意:通過createElement創(chuàng)建的元素并不屬于html文檔,它只是創(chuàng)建出來流昏,并未添加到html文檔中扎即,要調(diào)用appendChild或insertBefore等方法將其添加到HTML文檔樹中。

createTextNode大致同上

createTextNode接收一個(gè)參數(shù)况凉,這個(gè)參數(shù)就是文本節(jié)點(diǎn)中的文本谚鄙,和createElement一樣,創(chuàng)建后的文本節(jié)點(diǎn)也只是獨(dú)立的一個(gè)節(jié)點(diǎn)刁绒,同樣需要appendChild將其添加到HTML文檔樹中

cloneNode

cloneNode是用來返回調(diào)用方法的節(jié)點(diǎn)的一個(gè)副本闷营,它接收一個(gè)boolean參數(shù),用來表示是否復(fù)制子元素膛锭,使用如下:

var?parent?=?document.getElementById("parentElement");

var?parent2?=?parent.cloneNode(true);// 傳入true

?parent2.id?=?"parent2";

這段代碼通過cloneNode復(fù)制了一份parent元素粮坞,其中cloneNode的參數(shù)為true蚊荣,表示parent的子節(jié)點(diǎn)也被復(fù)制初狰,如果傳入false,則表示只復(fù)制了parent節(jié)點(diǎn)互例。

這段代碼很簡(jiǎn)單奢入,主要是綁定button事件,事件內(nèi)容是復(fù)制了一個(gè)parent媳叨,修改其id腥光,然后添加到文檔中。這里有幾點(diǎn)要注意:

(1)和createElement一樣糊秆,cloneNode創(chuàng)建的節(jié)點(diǎn)只是游離有html文檔外的節(jié)點(diǎn)武福,要調(diào)用appendChild方法才能添加到文檔樹中

(2)如果復(fù)制的元素有id,則其副本同樣會(huì)包含該id痘番,由于id具有唯一性捉片,所以在復(fù)制節(jié)點(diǎn)后必須要修改其id

(3)調(diào)用接收的bool參數(shù)最好傳入,如果不傳入該參數(shù)汞舱,不同瀏覽器對(duì)其默認(rèn)值的處理可能不同

除此之外伍纫,我們還有一個(gè)需要注意的點(diǎn):如果被復(fù)制的節(jié)點(diǎn)綁定了事件,則副本也會(huì)跟著綁定該事件嗎昂芜?這里要分情況討論:(1)如果是通過addEventListener或者比如onclick進(jìn)行綁定事件莹规,則副本節(jié)點(diǎn)不會(huì)綁定該事件(2)如果是內(nèi)聯(lián)方式綁定比如<div onclick="showParent()"></div>這樣的話,副本節(jié)點(diǎn)同樣會(huì)觸發(fā)事件泌神。

createDocumentFragment

createDocumentFragment方法用來創(chuàng)建一個(gè)DocumentFragment良漱。前面說到的DocumentFragment表示一種輕量級(jí)的文檔,它的作用主要是存儲(chǔ)臨時(shí)的節(jié)點(diǎn)用來準(zhǔn)備添加到文檔中债热。

這段代碼將按鈕綁定了一個(gè)事件砾嫉,這個(gè)事件創(chuàng)建了100個(gè)li節(jié)點(diǎn),然后依次將其添加HTML文檔中窒篱。這樣做有一個(gè)缺點(diǎn):每次一創(chuàng)建一個(gè)新的元素焕刮,然后添加到文檔樹中,這個(gè)過程會(huì)造成瀏覽器的回流墙杯。所謂回流簡(jiǎn)單說就是指元素大小和位置會(huì)被重新計(jì)算配并,如果添加的元素太多,會(huì)造成性能問題高镐。這個(gè)時(shí)候溉旋,就是使createDocumentFragment了。

創(chuàng)建型 總結(jié)

創(chuàng)建型API主要包括createElement嫉髓、createTextNode观腊、cloneNode、和createDocumentFragment四個(gè)方法算行,需要注意下面幾點(diǎn):

(1)它們創(chuàng)建的節(jié)點(diǎn)只是一個(gè)孤立的節(jié)點(diǎn)梧油,要通過appendChild添加到文檔中。

(2)cloneNode要注意如果被復(fù)制的節(jié)點(diǎn)是否包含子節(jié)點(diǎn)以及事件綁定等問題

(3)使用createDocumentFragment來解決添加大量節(jié)點(diǎn)時(shí)的性能問題

修改型

修改頁面內(nèi)容的API主要包括:appendChild州邢,insertBefore儡陨,removeChild,replaceChild量淌。

appendChild

appendChild我們?cè)谇懊嬉呀?jīng)用到多次骗村,就是將指定的節(jié)點(diǎn)添加到調(diào)用該方法的節(jié)點(diǎn)的子元素的末尾。調(diào)用方法如下:parent.appendChild(child);child節(jié)點(diǎn)將會(huì)作為parent節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)?這個(gè)方法很簡(jiǎn)單呀枢,但是有一點(diǎn)需要注意:如果被添加的節(jié)點(diǎn)是一個(gè)頁面中存在的節(jié)點(diǎn)胚股,則執(zhí)行后這個(gè)節(jié)點(diǎn)將會(huì)添加到指定位置,其原本所在的位置將移除該節(jié)點(diǎn)裙秋,也就是說不會(huì)同時(shí)存在兩個(gè)該節(jié)點(diǎn)在頁面上琅拌,相當(dāng)于把這個(gè)節(jié)點(diǎn)移動(dòng)到另一個(gè)地方。

這段代碼主要是獲取頁面上的child節(jié)點(diǎn)残吩,然后添加到指定位置财忽,可以看到原本的child節(jié)點(diǎn)被移動(dòng)到parent中了。這里還有一個(gè)要注意的點(diǎn):如果child綁定了事件泣侮,被移動(dòng)時(shí)即彪,它依然綁定著該事件。

insertBefore

insertBefore用來添加一個(gè)節(jié)點(diǎn)到一個(gè)參照節(jié)點(diǎn)之前,用法如下:

parentNode.insertBefore(newNode,refNode);

parentNode表示新節(jié)點(diǎn)被添加后的父節(jié)點(diǎn)

newNode表示要添加的節(jié)點(diǎn)

refNode表示參照節(jié)點(diǎn)隶校,新節(jié)點(diǎn)會(huì)添加到這個(gè)節(jié)點(diǎn)之前

關(guān)于第二個(gè)參數(shù)參照節(jié)點(diǎn)還有幾個(gè)注意的地方:

(1)refNode是必傳的漏益,如果不傳該參數(shù)會(huì)報(bào)錯(cuò)

(2)如果refNode是undefined或null,則insertBefore會(huì)將節(jié)點(diǎn)添加到子元素的末尾

removeChild

removeChild顧名思義深胳,就是刪除指定的子節(jié)點(diǎn)并返回绰疤,用法如下:

var?deletedChild?=?parent.removeChild(node);

deletedChild指向被刪除節(jié)點(diǎn)的引用,它等于node舞终,被刪除的節(jié)點(diǎn)仍然存在于內(nèi)存中轻庆,可以對(duì)其進(jìn)行下一步操作。

注意:如果被刪除的節(jié)點(diǎn)不是其子節(jié)點(diǎn)敛劝,則程序?qū)?huì)報(bào)錯(cuò)余爆。我們可以通過下面的方式來確保可以刪除:

if(node.parentNode){

node.parentNode.removeChild(node);

}

通過節(jié)點(diǎn)自己獲取節(jié)點(diǎn)的父節(jié)點(diǎn)夸盟,然后將自身刪除蛾方。

replaceChild

replaceChild用于使用一個(gè)節(jié)點(diǎn)替換另一個(gè)節(jié)點(diǎn),用法如下:parent.replaceChild(newChild,oldChild);

newChild是替換的節(jié)點(diǎn)上陕,可以是新的節(jié)點(diǎn)桩砰,也可以是頁面上的節(jié)點(diǎn),如果是頁面上的節(jié)點(diǎn)释簿,則其將被轉(zhuǎn)移到新的位置亚隅,oldChild是被替換的節(jié)點(diǎn)。

頁面修改型api主要是這四個(gè)接口辕万,要注意幾個(gè)特點(diǎn):

(1)不管是新增還是替換節(jié)點(diǎn)枢步,如果新增或替換的節(jié)點(diǎn)是原本存在頁面上的沉删,則其原來位置的節(jié)點(diǎn)將被移除渐尿,也就是說同一個(gè)節(jié)點(diǎn)不能存在于頁面的多個(gè)位置

(2)節(jié)點(diǎn)本身綁定的事件不會(huì)消失,會(huì)一直保留著矾瑰。

節(jié)點(diǎn)查詢型API

document.getElementById

這個(gè)接口很簡(jiǎn)單砖茸,根據(jù)元素id返回元素,返回值是Element類型殴穴,如果不存在該元素凉夯,則返回null。?使用這個(gè)接口有幾點(diǎn)要注意:

(1)元素的Id是大小寫敏感的采幌,一定要寫對(duì)元素的id

(2)HTML文檔中可能存在多個(gè)id相同的元素劲够,則返回第一個(gè)元素

(3)只從文檔中進(jìn)行搜索元素,如果創(chuàng)建了一個(gè)元素并指定id休傍,但并沒有添加到文檔中征绎,則這個(gè)元素是不會(huì)被查找到的

document.getElementsByTagName

這個(gè)接口根據(jù)元素標(biāo)簽名獲取元素,返回一個(gè)即時(shí)的HTMLCollection類型磨取,什么是即時(shí)的HTMLCollection類型呢人柿?

這個(gè)方法有幾點(diǎn)要注意:

(1)如果要對(duì)HTMLCollection集合進(jìn)行循環(huán)操作柴墩,最好將其長(zhǎng)度緩存起來,因?yàn)槊看窝h(huán)都會(huì)去計(jì)算長(zhǎng)度凫岖,暫時(shí)緩存起來可以提高效率

(2)如果沒有存在指定的標(biāo)簽江咳,該接口返回的不是null,而是一個(gè)空的HTMLCollection

(3)“ * ”表示所有標(biāo)簽

一個(gè)按鈕是顯示HTMLCollection元素的個(gè)數(shù)哥放,另一個(gè)按鈕可以新增一個(gè)div標(biāo)簽到文檔中歼指。前面提到HTMLCollcetion元素是即時(shí)的表示該集合是隨時(shí)變化的,也就是是文檔中有幾個(gè)div甥雕,它會(huì)隨時(shí)進(jìn)行變化东臀,當(dāng)我們新增一個(gè)div后,再訪問HTMLCollection時(shí)犀农,就會(huì)包含這個(gè)新增的div惰赋。

document.getElementsByName

getElementsByName主要是通過指定的name屬性來獲取元素,它返回一個(gè)即時(shí)的NodeList對(duì)象呵哨。使用這個(gè)接口主要要注意幾點(diǎn):

(1)返回對(duì)象是一個(gè)即時(shí)的NodeList赁濒,它是隨時(shí)變化的

(2)在HTML元素中,并不是所有元素都有name屬性孟害,比如div是沒有name屬性的拒炎,但是如果強(qiáng)制設(shè)置div的name屬性,它也是可以被查找到的

(3)在IE中挨务,如果id設(shè)置成某個(gè)值击你,然后傳入getElementsByName的參數(shù)值和id值一樣,則這個(gè)元素是會(huì)被找到的谎柄,所以最好不好設(shè)置同樣的值給id和name

擴(kuò)展

一.選擇符API

1.querySelector()方法

該方法接收一個(gè)CSS選擇符丁侄,返回與該模式匹配的第一個(gè)元素,如果沒有找到匹配的元素朝巫,返回null鸿摇。

通過Document類型調(diào)用querySelector()方法時(shí),會(huì)在文檔元素的范圍內(nèi)查找匹配的元素劈猿。而通過Element類型調(diào)用querySelector()方法時(shí)拙吉,只會(huì)在該元素后代元素的范圍內(nèi)查找匹配的元素。

注:眾多JavaScript庫中最常用的一項(xiàng)功能揪荣,就是根據(jù)CSS選擇符選擇與某個(gè)模式匹配的DOM元素筷黔。實(shí)際上,jQuery的核心就是通過CSS選擇符查詢DOM文檔取得元素的引用仗颈,從而拋開了getElementById()和getElementByTagName()佛舱。

CSS選擇符可以簡(jiǎn)單也可以復(fù)雜,視情況而定。如果傳入了不被支持的選擇符名眉,querySelector()會(huì)拋出錯(cuò)誤粟矿。

2.querySelectorAll()

querySelectorAll()方法接受的參數(shù)與querySelector()方法一樣,都是一個(gè)CSS選擇符损拢,但是返回的不僅不僅是一個(gè)元素陌粹,而是一個(gè)NodeList的實(shí)例。

與querySlector()一樣能夠調(diào)querySlectorAll()方法的有document福压,element掏秩,DocumentFragment。

要取得返回的NodeList中的每一個(gè)元素荆姆,可以使用item()方法蒙幻,也可以使用方括號(hào)語法,比如:

getElementsByClassName()

1)使用方法:element.getElementsByClassName("classNames")胆筒,其中邮破,element是有效的DOM元素(包括document) ? ? ? ?

classNames是CSS類名稱的組合(多個(gè)類名之間用空格,可以是多個(gè)空格隔開)仆救,如

element.getElementsByClassName("class2 class1")

將選取elements后代元素中同時(shí)應(yīng)用了class1和class2樣式的元素(樣式名稱不區(qū)分先后順序) ? ?2)說明:a. 返回值是一個(gè)nodeList集合(區(qū)別于Array? 有明確的定義與概念)

? ? ? ? ? ? ? ? ? b. 該方法只能選取調(diào)用該方法的元素的后代元素抒和。

?3)兼容性:IE8及其以下版本的瀏覽器未實(shí)現(xiàn)getElementsByClassName方法

HTML5添加的getElementsByClassName()方法,可以通過Document對(duì)象及所有HTML元素調(diào)用該方法

事件

所謂事件彤蔽,就是文檔或?yàn)g覽器窗口中發(fā)生的一些特定的交互瞬間

一摧莽、事件流

在頁面上,單擊某個(gè)元素的同時(shí)顿痪,也單擊了它的包含容器镊辕。事件流就是描述的從頁面中接收事件的順序。IE是事件冒泡流蚁袭,Netscape是事件捕獲流征懈。

事件冒泡

事件開始時(shí),由最具體的元素(文檔中嵌套最深的那個(gè)節(jié)點(diǎn))接收撕阎,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)(文檔)受裹;(所有現(xiàn)代瀏覽器都支持事件冒泡) 如果單擊了頁面中的<div>元素碌补,那么這個(gè)click事件會(huì)按照如下順序傳播:

(1)<div>

(2)<body>

(3)<html>

(4)document

事件捕獲

不太具體的節(jié)點(diǎn)最早接收到事件虏束,最具體的節(jié)點(diǎn)最后接收到事件。(老版本瀏覽器不支持)如果單擊了頁面中的<div>元素厦章,那么這個(gè)click事件會(huì)按照如下順序傳播:

(1)document

(2)<html>

(3)<body>

(4)<div>

二镇匀、DOM事件流

DOM2級(jí)事件規(guī)定的事件流包括三個(gè)階段:

1、事件捕獲階段

2袜啃、處于目標(biāo)階段

3汗侵、事件冒泡階段

在DOM事件流中,實(shí)際的目標(biāo)(div元素)在捕獲階段不會(huì)接受到事件。這意味著在捕獲階段晰韵,事件從document到<html>再到<body>后就停止了发乔。下一階段是”處于目標(biāo)”階段,于是事件在<div>上發(fā)生雪猪,并在事件處理中被看成冒泡階段的一部分栏尚。然后,冒泡階段發(fā)生只恨,事件又傳播回文檔译仗。

多數(shù)支持DOM事件流的瀏覽器都實(shí)現(xiàn)了一種特定的行為:即使”DOM2級(jí)事件”規(guī)范明確要求捕獲階段不會(huì)涉及事件目標(biāo),但I(xiàn)E9官觅、Safari纵菌、Chrome、Firefox和Opera9.5及更高版本都會(huì)在捕獲階段觸發(fā)事件對(duì)象上的事件休涤。結(jié)果咱圆,就是有兩個(gè)機(jī)會(huì)在目標(biāo)對(duì)象上面操作事件。

瀏覽器的內(nèi)核

主要分成兩部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎功氨。?渲染引擎:負(fù)責(zé)取得網(wǎng)頁的內(nèi)容(HTML闷堡、XML、圖像等等)疑故、整理訊息(例如加入CSS等)杠览,以及計(jì)算網(wǎng)頁的顯示方式,然后會(huì)輸出至顯示器或打印機(jī)纵势。瀏覽器的內(nèi)核的不同對(duì)于網(wǎng)頁的語法解釋會(huì)有不同踱阿,所以渲染的效果也不相同。所有網(wǎng)頁瀏覽器钦铁、電子郵件客戶端以及其它需要編輯软舌、顯示網(wǎng)絡(luò)內(nèi)容的應(yīng)用程序都需要內(nèi)核。?JS引擎則:解析和執(zhí)行javascript來實(shí)現(xiàn)網(wǎng)頁的動(dòng)態(tài)效果牛曹。?最開始渲染引擎和JS引擎并沒有區(qū)分的很明確佛点,后來JS引擎越來越獨(dú)立,內(nèi)核就傾向于只指渲染引擎黎比。


解析html以構(gòu)建dom樹 -> 構(gòu)建render樹 -> 布局render樹 -> 繪制render樹超营。

當(dāng)瀏覽器獲得一個(gè)html文件時(shí),會(huì)“自上而下”加載阅虫,并在加載過程中進(jìn)行解析渲染演闭。?

解析:?

1. 瀏覽器會(huì)將HTML解析成一個(gè)DOM樹,DOM 樹的構(gòu)建過程是一個(gè)深度遍歷過程:當(dāng)前節(jié)點(diǎn)的所有子節(jié)點(diǎn)都構(gòu)建好后才會(huì)去構(gòu)建當(dāng)前節(jié)點(diǎn)的下一個(gè)兄弟節(jié)點(diǎn)颓帝。?

2. 將CSS解析成 CSS Rule Tree 米碰。?

3. 根據(jù)DOM樹和CSSOM來構(gòu)造 Rendering Tree窝革。

注意:Rendering Tree 渲染樹并不等同于 DOM 樹,因?yàn)橐恍┫?Header 或 display:none 的東西就沒必要放在渲染樹中了吕座。

4.有了Render Tree虐译,瀏覽器已經(jīng)能知道網(wǎng)頁中有哪些節(jié)點(diǎn)、各個(gè)節(jié)點(diǎn)的CSS定義以及他們的從屬關(guān)系吴趴。下一步操作稱之為L(zhǎng)ayout菱蔬,顧名思義就是計(jì)算出每個(gè)節(jié)點(diǎn)在屏幕中的位置。?

5.再下一步就是繪制史侣,即遍歷render樹拴泌,并使用UI后端層繪制每個(gè)節(jié)點(diǎn)。

上述過程是逐步完成的惊橱,為了更好的用戶體驗(yàn)蚪腐,渲染引擎將會(huì)盡可能早的將內(nèi)容呈現(xiàn)到屏幕上,并不會(huì)等到所有的html都解析完成之后再去構(gòu)建和布局render樹税朴。它是解析完一部分內(nèi)容就顯示一部分內(nèi)容回季,同時(shí),可能還在通過網(wǎng)絡(luò)下載其余內(nèi)容正林。

(1)Reflow(回流):瀏覽器要花時(shí)間去渲染泡一,當(dāng)它發(fā)現(xiàn)了某個(gè)部分發(fā)生了變化影響了布局,那就需要倒回去重新渲染觅廓。?

(2)Repaint(重繪):如果只是改變了某個(gè)元素的背景顏色鼻忠,文字顏色等,不影響元素周圍或內(nèi)部布局的屬性杈绸,將只會(huì)引起瀏覽器的repaint帖蔓,重畫某一部分。

Reflow要比Repaint更花費(fèi)時(shí)間瞳脓,也就更影響性能塑娇。所以在寫代碼的時(shí)候,要盡量避免過多的Reflow劫侧。

reflow的原因:

(1)頁面初始化的時(shí)候埋酬;?

(2)操作DOM時(shí);?

(3)某些元素的尺寸變了烧栋;?

(4)如果 CSS 的屬性發(fā)生變化了写妥。

減少 reflow/repaint

(1)不要一條一條地修改 DOM 的樣式。與其這樣劲弦,還不如預(yù)先定義好 css 的 class耳标,然后修改 DOM 的 className。?

(2)不要把 DOM 結(jié)點(diǎn)的屬性值放在一個(gè)循環(huán)里當(dāng)成循環(huán)里的變量邑跪。?

(3)為動(dòng)畫的 HTML 元件使用 fixed 或 absoult 的 position次坡,那么修改他們的 CSS 是不會(huì) reflow 的。?

(4)千萬不要使用 table 布局画畅。因?yàn)榭赡芎苄〉囊粋€(gè)小改動(dòng)會(huì)造成整個(gè) table 的重新布局砸琅。

編寫CSS時(shí)應(yīng)該注意:

CSS選擇符是從右到左進(jìn)行匹配的。從右到左轴踱,所以症脂,#nav li 我們以為這是一條很簡(jiǎn)單的規(guī)則,秒秒鐘就能匹配到想要的元素淫僻,但是诱篷,但是,但是雳灵,是從右往左匹配啊棕所,所以,會(huì)去找所有的li悯辙,然后再去確定它的父元素是不是#nav琳省。,因此躲撰,寫css的時(shí)候需要注意:

(1)dom深度盡量淺针贬。

(2)減少inline javascript、css的數(shù)量拢蛋。

(3)使用現(xiàn)代合法的css屬性桦他。

(4)不要為id選擇器指定類名或是標(biāo)簽,因?yàn)閕d可以唯一確定一個(gè)元素谆棱。

(5)避免后代選擇符瞬铸,盡量使用子選擇符。

原因:子元素匹配符的概率要大于后代元素匹配符础锐。后代選擇符;#tp p{} 子選擇符:#tp>p{}

(6)避免使用通配符嗓节,舉一個(gè)例子:?

.mod .hd *{font-size:14px;}

?根據(jù)匹配順序,將首先匹配通配符,也就是說先匹配出通配符,然后匹配.hd(就是要對(duì)dom樹上的所有節(jié)點(diǎn)進(jìn)行遍歷他的父級(jí)元素),然后匹配.mod,這樣的性能耗費(fèi)可想而知.

博客園:http://www.cnblogs.com/duanyingkui/p/7327858.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市皆警,隨后出現(xiàn)的幾起案子拦宣,更是在濱河造成了極大的恐慌,老刑警劉巖信姓,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鸵隧,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡意推,警方通過查閱死者的電腦和手機(jī)豆瘫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來菊值,“玉大人外驱,你說我怎么就攤上這事育灸。” “怎么了昵宇?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵磅崭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我瓦哎,道長(zhǎng)砸喻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任蒋譬,我火速辦了婚禮割岛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘犯助。我一直安慰自己癣漆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布也切。 她就那樣靜靜地躺著扑媚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雷恃。 梳的紋絲不亂的頭發(fā)上疆股,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音倒槐,去河邊找鬼旬痹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛讨越,可吹牛的內(nèi)容都是我干的两残。 我是一名探鬼主播,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼把跨,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼人弓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起着逐,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤崔赌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后耸别,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體健芭,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年秀姐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慈迈。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡省有,死狀恐怖痒留,靈堂內(nèi)的尸體忽然破棺而出谴麦,到底是詐尸還是另有隱情,我是刑警寧澤狭瞎,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布细移,位于F島的核電站搏予,受9級(jí)特大地震影響熊锭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雪侥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一碗殷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧速缨,春花似錦锌妻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至原茅,卻和暖如春吭历,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背擂橘。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工晌区, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人通贞。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓朗若,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親昌罩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哭懈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Node類型 DOM1級(jí)定義了一個(gè)Node接口,該接口由DOM中所有節(jié)點(diǎn)類型實(shí)現(xiàn)茎用。這個(gè)Node接口在JS中是作為N...
    Maggie_77閱讀 422評(píng)論 0 0
  • 本章內(nèi)容 理解包含不同層次節(jié)點(diǎn)的 DOM 使用不同的節(jié)點(diǎn)類型 克服瀏覽器兼容性問題及各種陷阱 DOM 是針對(duì) HT...
    悶油瓶小張閱讀 642評(píng)論 0 1
  • P.E.T.父母效能訓(xùn)練課程模型的遣总,一個(gè)核心理念就是問題歸屬原則。(這里的問題指的是:誰的內(nèi)在需求沒有得到滿...
    雙雙YM閱讀 564評(píng)論 0 0
  • 晚上9:17,忙了一天夯辖,我真想睡覺琉预。但有一件事,讓我沒辦法睡安穩(wěn)蒿褂。 那就是今天的日記是昨晚湊數(shù)寫的圆米。 是啊卒暂,今天太...
    衛(wèi)紅教練閱讀 997評(píng)論 0 2
  • 北京和倫敦,相隔了12304公里娄帖,一個(gè)是現(xiàn)代中國(guó)崛起的象征也祠,一個(gè)是西方世界繁榮的先驅(qū)。一個(gè)是我大學(xué)求學(xué)之地近速,在這里...
    理性沉淀閱讀 412評(píng)論 0 2