JS高程:讀書摘要(七)DOM

一螃概、 DOM

DOM(文檔對(duì)象模型)是針對(duì)HTMLXML文檔的一個(gè)API(應(yīng)用程序編程接口)砍聊。DOM描繪了一個(gè)層次化的節(jié)點(diǎn)樹丈氓,允許開發(fā)人員添加、移除和修改頁面的某一部分宫纬。DOM脫胎于Netscape 及微軟公司創(chuàng)始的DHTML(動(dòng)態(tài)HTML)焚挠,但現(xiàn)在它已經(jīng)成為表現(xiàn)和操作頁面標(biāo)記的真正的跨平臺(tái)、語言中立的方式漓骚。

Node類型

DOM1級(jí)定義了一個(gè)Node接口蝌衔,該接口將由DOM 中的所有節(jié)點(diǎn)類型實(shí)現(xiàn)榛泛。每個(gè)節(jié)點(diǎn)都有一個(gè)nodeType屬性,用于表明節(jié)點(diǎn)的類型胚委。節(jié)點(diǎn)類型由在Node 類型中定義的下列12 個(gè)數(shù)值常量來表示挟鸠,任何節(jié)點(diǎn)類型必居其一:

節(jié)點(diǎn)類型nodeType

節(jié)點(diǎn)的nodeName和nodeValue

  • 節(jié)點(diǎn)關(guān)系

每個(gè)節(jié)點(diǎn)都有一個(gè)childNodes屬性,其中保存著一個(gè)NodeList 對(duì)象亩冬。NodeList是一種類數(shù)組對(duì)象(可以通過下標(biāo)訪問艘希,有length屬性,但它并不是Array的實(shí)例)硅急,用于保存一組有序的節(jié)點(diǎn)覆享,可以通過位置(索引 / 方括號(hào)寫法)來訪問這些節(jié)點(diǎn)。NodeList對(duì)象的獨(dú)特之處在于营袜,它實(shí)際上是基于DOM 結(jié)構(gòu)動(dòng)態(tài)執(zhí)行查詢的結(jié)果撒顿,因此DOM結(jié)構(gòu)的變化能夠自動(dòng)反映在NodeList 對(duì)象中。我們常說荚板,NodeList是有生命凤壁、有呼吸的對(duì)象,而不是在我們第一次訪問它們的某個(gè)瞬間拍攝下來的一張快照跪另。

如何訪問保存在NodeList中的節(jié)點(diǎn)——可以通過方括號(hào)拧抖,也可以使用item()方法。

var firstChild = someNode.childNodes[0];
var secondChild = someNode.childNodes.item(1);
var count = someNode.childNodes.length;

使用Array.prototype.slice()方法可以將NodeList對(duì)象轉(zhuǎn)換為數(shù)免绿。

var arrayOfNodes = Array.prototype.slice.call(someNode.childNodes,0);
  • 節(jié)點(diǎn)關(guān)系的引用屬性

    • parentNode:該屬性指向文檔樹中的父節(jié)點(diǎn)
    • previousSibling:該屬性指向文檔書中的前一個(gè)兄弟節(jié)點(diǎn)唧席,第一個(gè)節(jié)點(diǎn)的previousSibling 屬性值為null
    • nextSibling:該屬性指向文檔書中的前一個(gè)兄弟節(jié)點(diǎn),最后一個(gè)節(jié)點(diǎn)的nextSibling屬性值為null
    • 父節(jié)點(diǎn)的firstChildlastChild屬性分別指向其childNodes 列表中的第一個(gè)和最后一個(gè)節(jié)點(diǎn) 中,someNode.firstChild 的值始終等于someNode.childNodes[0] 嘲驾, 而someNode.lastChild 的值始終等于someNode.childNodes [someNode.childNodes.length-1]淌哟。
  • 操作子節(jié)點(diǎn)

    • appendChild():用于向childNodes列表的末尾添加一個(gè)節(jié)點(diǎn)。添加節(jié)點(diǎn)后辽故,childNodes 的新增節(jié)點(diǎn)徒仓、父節(jié)點(diǎn)及以前的最后一個(gè)子節(jié)點(diǎn)的關(guān)系指針都會(huì)相應(yīng)地得到更新。更新完成后誊垢,appendChild()返回新增的節(jié)點(diǎn)蓬衡。如果傳入到appendChild()中的節(jié)點(diǎn)已經(jīng)是文檔的一部分了,那么該節(jié)點(diǎn)就會(huì)成為父節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)彤枢。
    • insertBefore():把節(jié)點(diǎn)放在childNodes列表中某個(gè)特定的位置上,這個(gè)方法接受兩個(gè)參數(shù):要插入的節(jié)點(diǎn)和作為參照的節(jié)點(diǎn)筒饰。插入節(jié)點(diǎn)后缴啡,被插入的節(jié)點(diǎn)會(huì)變成參照節(jié)點(diǎn)的前一個(gè)同胞節(jié)點(diǎn)(previousSibling),同時(shí)被方法返回瓷们。如果參照節(jié)點(diǎn)是null业栅,則insertBefore()appendChild()執(zhí)行相同的操作秒咐。
    • replaceChild():這個(gè)方法接受兩個(gè)參數(shù),要插入的節(jié)點(diǎn)和要替換的節(jié)點(diǎn)碘裕。要替換的節(jié)點(diǎn)將由這個(gè)方法返回并從文檔樹中被移除携取,同時(shí)由要插入的節(jié)點(diǎn)占據(jù)其位置。在使用replaceChild()插入一個(gè)節(jié)點(diǎn)時(shí)帮孔,該節(jié)點(diǎn)的所有關(guān)系指針都會(huì)從被它替換的節(jié)點(diǎn)復(fù)制過來雷滋。盡管從技術(shù)上講,被替換的節(jié)點(diǎn)仍然還在文檔中文兢,但它在文檔中已經(jīng)沒有了自己的位置晤斩。
    • removeChild():這個(gè)方法接受一個(gè)參數(shù),即要移除的節(jié)點(diǎn)姆坚。被移除的節(jié)點(diǎn)將成為方法的返回值澳泵。
  • 操作節(jié)點(diǎn)的其他方法

    • cloneNode(),用于創(chuàng)建調(diào)用這個(gè)方法的節(jié)點(diǎn)的一個(gè)完全相同的副本兼呵。cloneNode()方法接受一個(gè)布爾值參數(shù)兔辅,表示是否執(zhí)行深復(fù)制。在參數(shù)為true的情況下击喂,執(zhí)行深復(fù)制维苔,也就是復(fù)制節(jié)點(diǎn)及其整個(gè)子節(jié)點(diǎn)樹;在參數(shù)為false的情況下茫负,執(zhí)行淺復(fù)制蕉鸳,即只復(fù)制節(jié)點(diǎn)本身。復(fù)制后返回的節(jié)點(diǎn)副本屬于文檔所有忍法,但并沒有為它指定父節(jié)點(diǎn)潮尝。因此,這個(gè)節(jié)點(diǎn)副本就成為了一個(gè)“孤兒”饿序,除非通過appendChild()勉失、insertBefore()replaceChild()將它添加到文檔中。
    • normalize()原探,由于解析器的實(shí)現(xiàn)或DOM操作等原因乱凿,可能會(huì)出現(xiàn)文本節(jié)點(diǎn)不包含文本,或者接連出現(xiàn)兩個(gè)文本節(jié)點(diǎn)的情況咽弦。當(dāng)在某個(gè)節(jié)點(diǎn)上調(diào)用這個(gè)方法時(shí)徒蟆,就會(huì)在該節(jié)點(diǎn)的后代節(jié)點(diǎn)中查找上述兩種情況。如果找到了空文本節(jié)點(diǎn)型型,則刪除它段审;如果找到相鄰的文本節(jié)點(diǎn),則將它們合并為一個(gè)文本節(jié)點(diǎn)闹蒜。
var deepList = myList.cloneNode(true);
alert(deepList.childNodes.length); //3(IE < 9)或7(其他瀏覽器)

var shallowList = myList.cloneNode(false);
alert(shallowList.childNodes.length); //0

cloneNode()方法不會(huì)復(fù)制添加到DOM節(jié)點(diǎn)中的JavaScript屬性寺枉,例如事件處理程序等抑淫。這個(gè)方法只復(fù)制特性、(在明確指定的情況下也復(fù)制)子節(jié)點(diǎn)姥闪,其他一切都不會(huì)復(fù)制始苇。IE 在此存在一個(gè)bug,即它會(huì)復(fù)制事件處理程序筐喳,所以我們建議在復(fù)制之前最好先移除事件處理程序催式。

二、 Document 類型

document對(duì)象:在瀏覽器中疏唾,document對(duì)象是HTMLDocument(繼承自Document類型)的一個(gè)實(shí)例蓄氧,表示整個(gè)HTML頁面。而且槐脏,document 對(duì)象是window 對(duì)象的一個(gè)屬性喉童,因此可以將其作為全局對(duì)象來訪問。通過這個(gè)文檔對(duì)象顿天,不僅可以取得與頁面有關(guān)的信息堂氯,而且還能操作頁面的外觀及其底層結(jié)構(gòu)。Document 節(jié)點(diǎn)具有下列特征: nodeType 的值為9牌废;nodeName 的值為"#document"咽白;nodeValue 的值為nullparentNode 的值為null鸟缕;

document對(duì)象的屬性

var html = document.documentElement; //取得對(duì)<html>的引用

var body = document.body; //取得對(duì)<body>的引用

var doctype = document.doctype; //取得對(duì)<DOCTYPE>文檔類型的引用

//取得文檔標(biāo)題
var originalTitle = document.title;
//設(shè)置文檔標(biāo)題
document.title = "New page title";

//取得完整的URL晶框,不可設(shè)置
var url = document.URL;

//取得域名,可設(shè)置懂从,但是不能隨便設(shè)置
var domain = document.domain;

//假設(shè)頁面來自p2p.wrox.com 域
document.domain = "wrox.com"; // 成功
document.domain = "nczonline.net"; // 出錯(cuò)授段! 只能省略域名

//取得來源頁面的URL,不可設(shè)置
var referrer = document.referrer;
查找元素

1番甩、getElementById():接收一個(gè)參數(shù):要取得的元素的ID侵贵。如果找到相應(yīng)的元素則返回該元素,如果不存在帶有相應(yīng)ID 的元素缘薛,則返回null窍育。注意,這里的ID必須與頁面中元素的id特性(attribute)嚴(yán)格匹配宴胧,包括大小寫漱抓。IE8 及較低版本不區(qū)分ID的大小寫,因此"myDiv""mydiv"會(huì)被當(dāng)作相同的元素ID恕齐。如果頁面中多個(gè)元素的ID 值相同辽旋,getElementById()只返回文檔中第一次出現(xiàn)的元素。

<input type="text" name="myElement" value="Text field">
<div id="myElement">A div</div>

基于這段HTML 代碼,在IE7 中調(diào)用document.getElementById("myElement ")补胚,結(jié)果會(huì)返回<input>元素;而在其他所有瀏覽器中追迟,都會(huì)返回對(duì)<div>元素的引用溶其。為了避免IE中存在的這個(gè)問題,最好的辦法是不讓表單(<input>敦间、<textarea>瓶逃、<button><select>)字段的name特性與其他元素的ID相同。

2廓块、getElementsByTagName()厢绝。這個(gè)方法接受一個(gè)參數(shù),即要取得元素的標(biāo)簽名带猴,返回一個(gè)HTMLCollection對(duì)象昔汉,作為一個(gè)“動(dòng)態(tài)”集合,返回所有的標(biāo)簽元素組成的類數(shù)組拴清。HTMLCollection 對(duì)象還有一個(gè)方法靶病,叫做namedItem(),使用這個(gè)方法可以通過元素的name特性取得集合中的項(xiàng)口予。例如娄周,

<img src="myimage.gif" name="myImage">
 // 那么就可以通過如下方式從images幾個(gè)中取得對(duì)應(yīng)name的<img>元素:
var images = document.getElementsByTagName("img");
var myImage = images.namedItem("myImage");

// HTMLCollection 還支持按名稱訪問項(xiàng)
var myImage = images["myImage"];

在通過元素調(diào)用這個(gè)方法時(shí),除了搜索起點(diǎn)是當(dāng)前元素之外沪停,其他方面都跟通過document調(diào)用這個(gè)方法相同煤辨,因此結(jié)果只會(huì)返回當(dāng)前元素的后代。

var ul = document.getElementById("myList");
var items = ul.getElementsByTagName("li");

3木张、getElementsByClassName():這個(gè)方法接受一個(gè)參數(shù)众辨,即要取得元素的類名,返回一個(gè)HTMLCollection對(duì)象窟哺,作為一個(gè)“動(dòng)態(tài)”集合泻轰,返回所有擁有該類的元素組成的類數(shù)組且轨。

4浮声、為訪問文檔常用的部分提供了快捷方式:

  • document.anchors旋奢,包含文檔中所有帶name特性的<a>元素;
  • document.forms矗钟,包含文檔中所有的<form>元素
  • document.images,包含文檔中所有的<img>元素
  • document.links躬它,包含文檔中所有帶href 特性的<a>元素。

這些特殊集合始終都可以通過HTMLDocument 對(duì)象訪問到东涡,而且冯吓,與HTMLCollection 對(duì)象類似,集合中的項(xiàng)也會(huì)隨著當(dāng)前文檔內(nèi)容的更新而更新疮跑。

文檔寫入

write()writeln()方法都接受一個(gè)字符串參數(shù)组贺,即要寫入到輸出流中的文本。write()會(huì)原樣寫入祖娘,而writeln()則會(huì)在字符串的末尾添加一個(gè)換行符(\n)失尖。在頁面被加載的過程中,可以使用這兩個(gè)方法向頁面中動(dòng)態(tài)地加入內(nèi)容贿条。方法open()close()分別用于打開和關(guān)閉網(wǎng)頁的輸出流雹仿。

<html>
    <head>
        <title>document.write() Example</title>
    </head>
    <body>
        <p>The current date and time is:
        <script type="text/javascript">
            document.write("<strong>" + (new Date()).toString() + "</strong>");
        </script>
        </p>
    </body>
</html>

這樣做會(huì)創(chuàng)建一個(gè)DOM元素,而且可以在將來訪問該元素整以。通過write()writeln()輸出的任何HTML代碼都將如此處理胧辽。

還可以使用write()writeln()方法動(dòng)態(tài)地包含外部資源,例如JavaScript文件等公黑。在包含JavaScript文件時(shí)邑商,必須注意不能像下面的例子那樣直接包含字符串"</script>",因?yàn)檫@會(huì)導(dǎo)致該字符串被解釋為腳本塊的結(jié)束凡蚜,它后面的代碼將無法執(zhí)行人断。應(yīng)該使用轉(zhuǎn)義符做處理"<\/script>"

window.onload事件處理程序,等到頁面完全加載之后延遲執(zhí)行函數(shù)朝蜘。函數(shù)執(zhí)行之后恶迈,調(diào)用document.write()會(huì)重寫整個(gè)頁面內(nèi)容。

三谱醇、Element 類型

Element 類型用于表現(xiàn)XMLHTML元素暇仲,提供了對(duì)元素標(biāo)簽名、子節(jié)點(diǎn)及特性的訪問副渴。Element節(jié)點(diǎn)具有以下特征:nodeType 的值為1奈附;nodeName 的值為元素的標(biāo)簽名;nodeValue 的值為null煮剧;

要訪問元素的標(biāo)簽名斥滤,可以使用nodeName屬性将鸵,也可以使用tagName屬性;這兩個(gè)屬性會(huì)返回相同的值佑颇。

所有HTML元素都由HTMLElement 類型表示顶掉,不是直接通過這個(gè)類型,也是通過它的子類型來表示漩符。HTMLElement類型直接繼承自Element并添加了一些屬性一喘。添加的這些屬性分別對(duì)應(yīng)于每個(gè)HTML元素中都存在的下列標(biāo)準(zhǔn)特性。

id嗜暴,元素在文檔中的唯一標(biāo)識(shí)符
title,有關(guān)元素的附加說明信息
lang议蟆,元素內(nèi)容的語言代碼闷沥,很少使用。
dir咐容,語言的方向舆逃,值有l(wèi)tr從左到右  rtl從右到做 ,很少使用

className戳粒,與元素的class 特性對(duì)應(yīng)路狮,即為元素指定的CSS類。
沒有將這個(gè)屬性命名為class蔚约,是因?yàn)閏lass 是ECMAScript 的保留字奄妨。
通過className訪問而不是class,**但是在使用操作元素屬性的方法時(shí)需要使用class苹祟,與html上的屬性保持一致**

<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>
操作元素屬性

每個(gè)元素都有一或多個(gè)特性砸抛,這些特性的用途是給出相應(yīng)元素或其內(nèi)容的附加信息。操作特性的DOM方法主要有三個(gè)树枫,分別是getAttribute()直焙、setAttribute()removeAttribute(),接受特性字符串作為第一個(gè)參數(shù)砂轻。setAttribute()可以傳第二個(gè)參數(shù)作為設(shè)置的新值奔誓。特性的名稱是不區(qū)分大小寫的,即"ID""id"代表的都是同一個(gè)特性搔涝。另外也要注意厨喂,根據(jù)HTML5規(guī)范,自定義特性應(yīng)該加上data-前綴以便驗(yàn)證体谒。

注意杯聚,傳遞給getAttribute()的特性名與實(shí)際的特性名相同。因此要想得到class特性值抒痒,應(yīng)該傳入"class"而不是"className"幌绍,后者只有在通過對(duì)象屬性訪問特性時(shí)才用。如果給定名稱的特性不存在,getAttribute()返回null傀广。

1颁独、 getAttribute()獲取屬性

任何元素的所有特性,也都可以通過DOM元素本身的屬性來訪問伪冰。不過誓酒,只有公認(rèn)的(非自定義的)特性才會(huì)以屬性的形式添加到DOM對(duì)象中。自定義屬性只能通過getAttribute()來獲得

<div id="myDiv" align="left" my_special_attribute="hello!"></div>

alert(div.id); //"myDiv"
alert(div.my_special_attribute); //undefined(IE 除外)
alert(div.align); //"left"

有兩類特殊的特性贮聂,它們雖然有對(duì)應(yīng)的屬性名靠柑,但屬性的值與通過getAttribute()返回的值并不相同。

  • 第一類特性就是style吓懈,用于通過CSS 為元素指定樣式歼冰。

    • 在通過getAttribute()訪問時(shí),返回的style特性值中包含的是CSS文本
    • 而通過屬性來訪問它則會(huì)返回一個(gè)對(duì)象耻警。由于style屬性是用于以編程方式訪問元素樣式的(本章后面討論)隔嫡,因此并沒有直接映射到style特性。
  • 第二類與眾不同的特性是onclick這樣的事件處理程序甘穿。

    • 如果通過getAttribute()訪問腮恩,則會(huì)返回相應(yīng)代碼的字符串。
    • 在訪問onclick屬性時(shí)温兼,則會(huì)返回一個(gè)JavaScript函數(shù)(如果未在元素中指定相應(yīng)特性秸滴,則返回null)。這是因?yàn)?code>onclick及其他事件處理程序?qū)傩员旧砭蛻?yīng)該被賦予函數(shù)值妨托。

由于存在這些差別缸榛,在通過JavaScript 以編程方式操作DOM時(shí),開發(fā)人員經(jīng)常不使用getAttribute()兰伤,而是只使用對(duì)象的屬性内颗。只有在取得自定義特性值的情況下,才會(huì)使用getAttribute()方法敦腔。

2均澳、 setAttribute()獲取屬性
setAttribute(),這個(gè)方法接受兩個(gè)參數(shù):要設(shè)置的特性名和值符衔。如果特性已經(jīng)存在找前,setAttribute()會(huì)以指定的值替換現(xiàn)有的值;如果特性不存在判族,setAttribute()則創(chuàng)建該屬性并設(shè)置相應(yīng)的值躺盛。通過setAttribute()方法既可以操作HTML特性也可以操作自定義特性。通過這個(gè)方法設(shè)置的特性名會(huì)被統(tǒng)一轉(zhuǎn)換為小寫形式形帮,即"ID"最終會(huì)變成"id"槽惫。如果是使用這樣的方式oDiv.myColor="div1"的方式設(shè)置的自定義屬性周叮,用getAttribute()是訪問不到的。

3界斜、 removeAttribute()刪除屬性
接受一個(gè)參數(shù)仿耽,即刪除的屬性key,這個(gè)方法用于徹底刪除元素的特性各薇。調(diào)用這個(gè)方法不僅會(huì)清除特性的值项贺,而且也會(huì)從元素中完全刪除特性,oDiv.removeAttribute("class");

創(chuàng)建元素

1峭判、 document.createElement() 創(chuàng)建元素
這個(gè)方法只接受一個(gè)參數(shù)开缎,即要?jiǎng)?chuàng)建元素的標(biāo)簽名(IE中可以傳入完整的HTML標(biāo)簽字符串)。這個(gè)標(biāo)簽名在HTML文檔中不區(qū)分大小寫林螃,而在XML(包括XHTML)文檔中啥箭,則是區(qū)分大小寫的。

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

2治宣、 增加元素

  • appendChild()ParentElement.appendChild(element); 在父元素末尾添加一個(gè)子元素
  • insertBefore()ParentElement.insertBefore(newElement,refElement); 指定的已有子節(jié)點(diǎn)之前插入新的子節(jié)點(diǎn)。

3砌滞、刪除元素

  • removeChild()ParentElement.removeChild(elelment); 在父元素中移除某個(gè)子元素

4侮邀、改變?cè)?/strong>

  • replaceChild()ParentElement.replaceChild(newElement,oldElement); 在父元素中替換某個(gè)子元素
元素的子節(jié)點(diǎn)

元素的childNodes屬性中包含了它的所有子節(jié)點(diǎn),這些子節(jié)點(diǎn)有可能是元素贝润、文本節(jié)點(diǎn)绊茧、注釋或處理指令。IE會(huì)返回所有的子元素節(jié)點(diǎn)打掘,而其他瀏覽器則返回所有的子節(jié)點(diǎn)华畏,這意味著在執(zhí)行某項(xiàng)操作以前,通常都要先檢查一下nodeTpye屬性

for (var i=0, len=element.childNodes.length; i < len; i++){
    if (element.childNodes[i].nodeType == 1){ 
        //對(duì)子元素節(jié)點(diǎn)執(zhí)行某些操作
    }
}

四尊蚁、Text 類型

每個(gè)可以包含內(nèi)容的元素最多只能有一個(gè)文本節(jié)點(diǎn)亡笑,而且必須確實(shí)有內(nèi)容存在。(只有空格也算是有內(nèi)容)

  • nodeType 的值為3横朋;
  • nodeName 的值為"#text"仑乌;
  • nodeValue 的值為節(jié)點(diǎn)所包含的文本;

如果這個(gè)文本節(jié)點(diǎn)當(dāng)前存在于文檔樹中琴锭,那么修改文本節(jié)點(diǎn)的結(jié)果就會(huì)立即得到反映晰甚。另外,在修改文本節(jié)點(diǎn)時(shí)還要注意决帖,此時(shí)的字符串會(huì)經(jīng)過HTML(或XML厕九,取決于文檔類型)編碼。換句話說地回,小于號(hào)扁远、大于號(hào)或引號(hào)都會(huì)像下面的例子一樣被轉(zhuǎn)義俊鱼。

Some <strong>other</strong> message 
轉(zhuǎn)義為
Some &lt;strong&gt;other&lt;/strong&gt; message
創(chuàng)建文本節(jié)點(diǎn)

document.createTextNode() : 創(chuàng)建新文本節(jié)點(diǎn),這個(gè)方法接受一個(gè)參數(shù)——要插入節(jié)點(diǎn)中的文本穿香。與設(shè)置已有文本節(jié)點(diǎn)的值一樣亭引,作為參數(shù)的文本也將按照HTMLXML 的格式進(jìn)行編碼。創(chuàng)建的文本節(jié)點(diǎn)皮获,可以使用元素的appendChild()將其添加到元素中焙蚓,在沒有添加進(jìn)DOM樹之前,都是屬于孤兒節(jié)點(diǎn)洒宝,文檔碎片购公。

var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);

一般情況下,每個(gè)元素只有一個(gè)文本子節(jié)點(diǎn)雁歌。不過宏浩,在某些情況下也可能包含多個(gè)文本子節(jié)點(diǎn),比如使用appendChild()方法多次添加文本節(jié)點(diǎn)靠瞎,那么這兩個(gè)節(jié)點(diǎn)中的文本就會(huì)連起來顯示比庄,中間不會(huì)有空格。如果在一個(gè)包含兩個(gè)或多個(gè)文本節(jié)點(diǎn)的父元素上調(diào)用normalize()方法乏盐,則會(huì)將所有文本節(jié)點(diǎn)合并成一個(gè)節(jié)點(diǎn)佳窑,結(jié)果節(jié)點(diǎn)的nodeValue等于將合并前每個(gè)文本節(jié)點(diǎn)的nodeValue 值拼接起來的值。

瀏覽器在解析文檔時(shí)永遠(yuǎn)不會(huì)創(chuàng)建相鄰的文本節(jié)點(diǎn)父能。這種情況只會(huì)作為執(zhí)行DOM操作的結(jié)果出現(xiàn)神凑。

五、DOM操作技術(shù)

DOM操作往往是JavaScript程序中開銷最大的部分何吝,而因訪問NodeList導(dǎo)致的問題最多溉委。NodeList對(duì)象都是“動(dòng)態(tài)的”,這就意味著每次訪問NodeList對(duì)象爱榕,都會(huì)運(yùn)行一次查詢瓣喊。有鑒于此,最好的辦法就是盡量減少DOM操作呆细。

動(dòng)態(tài)腳本

指的是在頁面加載時(shí)不存在型宝,但將來的某一時(shí)刻通過修改DOM動(dòng)態(tài)添加的腳本。

1絮爷、插入外部文件

function loadScript(url){
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = url; 
    document.body.appendChild(script); // 在這行代碼執(zhí)行之前都不會(huì)下載文件
}

loadScript("client.js");  // 方法調(diào)用時(shí) 動(dòng)態(tài)添加script標(biāo)簽 并執(zhí)行腳本

2趴酣、行內(nèi)方式,也是添加script標(biāo)簽 坑夯,但是腳本代碼吧不是從外部引入岖寞,而是本地添加進(jìn)去。所有寫在<script></script>標(biāo)簽對(duì)中的代碼都算是script元素的文本節(jié)點(diǎn)

var script = document.createElement("script");
script.type = "text/javascript";
script.text = "function sayHi(){alert('hi');}";
document.body.appendChild(script);

Safari 3.0 之前的版本不能正確地支持text屬性柜蜈,可以使用創(chuàng)建文本節(jié)點(diǎn)的方式解決仗谆。

function loadScriptString(code){
    var script = document.createElement("script");
    script.type = "text/javascript";
    try {
        script.appendChild(document.createTextNode(code));
    } catch (ex){
        script.text = code;
    }
    document.body.appendChild(script);
}

loadScriptString("function sayHi(){alert('hi');}");
動(dòng)態(tài)樣式

能夠把CSS 樣式包含到HTML 頁面中的元素有兩個(gè)指巡。其中,<link>元素用于包含來自外部的文件隶垮,而<style>元素用于指定嵌入的樣式藻雪。

同理。操作DOM代碼添加標(biāo)簽可以很容易地動(dòng)態(tài)創(chuàng)建出作用CSS樣式的元素:

1狸吞、外部引入link

function loadStyles(url){
    var link = document.createElement("link");
    link.rel = "stylesheet";
    link.type = "text/css";
    link.href = url;
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(link);
}

loadStyles("myStyle.css");

加載外部樣式文件的過程是異步的勉耀,也就是加載樣式與執(zhí)行JavaScript代碼的過程沒有固定的次序。

2蹋偏、內(nèi)部style

這種方式會(huì)實(shí)時(shí)地向頁面中添加樣式便斥,因此能夠馬上看到變化。

function loadStyleString(css){
    var style = document.createElement("style");
    style.type = "text/css";
    try{
        style.appendChild(document.createTextNode(css));
    } catch (ex){
        style.styleSheet.cssText = css;
    }
    var head = document.getElementsByTagName("head")[0];
    head.appendChild(style);
}

loadStyleString("body{background-color:red}");

事實(shí)上威始,IE 此時(shí)拋出的錯(cuò)誤(將<script> 枢纠、<style>視為一個(gè)特殊的元素,不允許DOM訪問其子節(jié)點(diǎn)黎棠。)晋渺。解決IE 中這個(gè)問題的辦法,就是訪問元素的styleSheet屬性脓斩,該屬性又有一個(gè)cssText屬性些举,可以接受CSS代碼

操作表格

為了方便構(gòu)建表格,HTML DOM還為<table>俭厚、<tbody><tr>元素添加了一些屬性和方法。

<table>元素添加的屬性和方法如下驶臊。

  • caption:保存著對(duì)<caption>元素(如果有)的指針挪挤。
  • tBodies:是一個(gè)<tbody>元素的HTMLCollection
  • tFoot:保存著對(duì)<tfoot>元素(如果有)的指針关翎。
  • tHead:保存著對(duì)<thead>元素(如果有)的指針扛门。
  • rows:是一個(gè)表格中所有行的HTMLCollection
  • createTHead():創(chuàng)建<thead>元素纵寝,將其放到表格中论寨,返回引用。
  • createTFoot():創(chuàng)建<tfoot>元素爽茴,將其放到表格中葬凳,返回引用。
  • createCaption():創(chuàng)建<caption>元素室奏,將其放到表格中火焰,返回引用。
  • deleteTHead():刪除<thead>元素胧沫。
  • deleteTFoot():刪除<tfoot>元素昌简。
  • deleteCaption():刪除<caption>元素占业。
  • deleteRow(pos):刪除指定位置的行。
  • insertRow(pos):向rows 集合中的指定位置插入一行纯赎。

<tbody>元素添加的屬性和方法如下谦疾。

  • rows:保存著<tbody>元素中行的HTMLCollection
  • deleteRow(pos):刪除指定位置的行犬金。
  • insertRow(pos):向rows 集合中的指定位置插入一行念恍,返回對(duì)新插入行的引用。

<tr>元素添加的屬性和方法如下佑附。

  • cells:保存著<tr>元素中單元格的HTMLCollection樊诺。
  • deleteCell(pos):刪除指定位置的單元格。
  • insertCell(pos):向cells 集合中的指定位置插入一個(gè)單元格音同,返回對(duì)新插入單元格的引用词爬。
使用NodeList

理解NodeList及其“近親”NamedNodeMapHTMLCollection,是從整體上透徹理解DOM的關(guān)鍵所在权均。這三個(gè)集合都是“動(dòng)態(tài)的”顿膨;換句話說,每當(dāng)文檔結(jié)構(gòu)發(fā)生變化時(shí)叽赊,它們都會(huì)得到更新恋沃。因此,它們始終都會(huì)保存著最新必指、最準(zhǔn)確的信息囊咏。從本質(zhì)上說,所有NodeList對(duì)象都是在訪問DOM文檔時(shí)實(shí)時(shí)運(yùn)行的查詢塔橡。

如果想要迭代一個(gè)NodeList梅割,最好是使用length屬性初始化第二個(gè)變量,然后將迭代器與該變量進(jìn)行比較葛家。因?yàn)?code>NodeList是動(dòng)態(tài)的户辞,NodeList.length也是動(dòng)態(tài)的,如果在迭代的過程對(duì)這個(gè)NodeList有添加Node的操作癞谒,將會(huì)無限迭代下去底燎,所以可以使用變量暫存length:var len = NodeList.length

一般來說,應(yīng)該盡量減少訪問NodeList 的次數(shù)弹砚。因?yàn)槊看卧L問NodeList双仍,都會(huì)運(yùn)行一次基于文檔的查詢。所以桌吃,可以考慮將從NodeList中取得的值緩存起來殊校。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市读存,隨后出現(xiàn)的幾起案子为流,更是在濱河造成了極大的恐慌残家,老刑警劉巖袱衷,帶你破解...
    沈念sama閱讀 218,451評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件噩峦,死亡現(xiàn)場(chǎng)離奇詭異币他,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)莲祸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門蹂安,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人锐帜,你說我怎么就攤上這事田盈。” “怎么了缴阎?”我有些...
    開封第一講書人閱讀 164,782評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵允瞧,是天一觀的道長。 經(jīng)常有香客問我蛮拔,道長述暂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評(píng)論 1 294
  • 正文 為了忘掉前任建炫,我火速辦了婚禮畦韭,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肛跌。我一直安慰自己艺配,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,733評(píng)論 6 392
  • 文/花漫 我一把揭開白布衍慎。 她就那樣靜靜地躺著妒挎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪西饵。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評(píng)論 1 305
  • 那天鳞芙,我揣著相機(jī)與錄音眷柔,去河邊找鬼。 笑死原朝,一個(gè)胖子當(dāng)著我的面吹牛驯嘱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播喳坠,決...
    沈念sama閱讀 40,320評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼鞠评,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了壕鹉?” 一聲冷哼從身側(cè)響起剃幌,我...
    開封第一講書人閱讀 39,241評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤聋涨,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后负乡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牍白,經(jīng)...
    沈念sama閱讀 45,686評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,878評(píng)論 3 336
  • 正文 我和宋清朗相戀三年抖棘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茂腥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,992評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡切省,死狀恐怖最岗,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情朝捆,我是刑警寧澤般渡,帶...
    沈念sama閱讀 35,715評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站右蹦,受9級(jí)特大地震影響诊杆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜何陆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,336評(píng)論 3 330
  • 文/蒙蒙 一晨汹、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贷盲,春花似錦淘这、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至佳魔,卻和暖如春曙聂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鞠鲜。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評(píng)論 1 270
  • 我被黑心中介騙來泰國打工宁脊, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贤姆。 一個(gè)月前我還...
    沈念sama閱讀 48,173評(píng)論 3 370
  • 正文 我出身青樓榆苞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親霞捡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坐漏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,947評(píng)論 2 355

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

  • 人一定都會(huì)做夢(mèng)。世界上不做夢(mèng)的只有兩種人:一是至人無夢(mèng)。至人是得道赊琳、成仙街夭、成佛的人,以及有最高智能的人慨畸。二是愚人無...
    何須灑酒閱讀 1,495評(píng)論 2 4
  • 當(dāng)初的過去的情誼 已不可追 我曾經(jīng)愛過的那個(gè)人你 十二年已經(jīng)過去 雖然有不舍 可終究沒能保護(hù)你 是我不夠好 所以難...
    植成喬木閱讀 148評(píng)論 0 0
  • 說到甜甜圈,大家第一印象可能就是簡(jiǎn)單的“yo弱卡,那個(gè)甜甜圈乃正,它又厚又甜” 今天我們介紹一家把甜甜圈當(dāng)做藝術(shù)品在賣的小...
    世界甜品閱讀 430評(píng)論 0 0
  • 感情上的失意,不是在乎婶博,而是在乎不起瓮具,因?yàn)槟阕钆率サ牟粦?yīng)是已經(jīng)擁有的東西,而是夢(mèng)想凡人。愛情如果只是一個(gè)過程名党,那么經(jīng)...
    丿啷個(gè)哩個(gè)啷閱讀 176評(píng)論 0 0