九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
使用 Dojo 的 Ajax 應(yīng)用開發(fā)進(jìn)階教程,第 4 部分: DOM 查詢與操作

DOM 的全稱是文檔對(duì)象模型(Document Object Model)。它是 HTML 和 XML 文檔的 API。它定義了文檔的邏輯結(jié)構(gòu),以及對(duì)文檔進(jìn)行訪問和操作的方式。通過 DOM,開發(fā)人員可以在文檔中自由導(dǎo)航, 也可以添加、更新和刪除其中的元素和內(nèi)容?;旧衔臋n中的任何內(nèi)容都是可以通過 DOM 進(jìn)行訪問和操作的。本文詳細(xì)介紹了如何使用 DOM 基本 API 和 Dojo 來進(jìn)行 DOM 查詢和操作。使用的 Dojo 版本是 1.4。下面首先介紹 DOM 的基本概念。

DOM 基本概念

DOM 是給腳本語(yǔ)言(如 JavaScript 和 VBScript 等)來使用的 API。在互聯(lián)網(wǎng)的早期,HTML 頁(yè)面都是靜態(tài)的。開發(fā)人員沒有辦法對(duì)頁(yè)面進(jìn)行動(dòng)態(tài)修改。DOM 的出現(xiàn)解決了這個(gè)問題。DOM 給出了一種描述 HTML 文檔結(jié)構(gòu)的方式,并且允許開發(fā)人員通過 DOM 提供的 API 來對(duì)文檔結(jié)構(gòu)進(jìn)行修改。DOM 目前是 W3C 的推薦規(guī)范。主流的瀏覽器都實(shí)現(xiàn)或部分實(shí)現(xiàn)該規(guī)范。下面首先介紹 DOM 規(guī)范的版本歷史。

DOM 規(guī)范的版本歷史

DOM 從出現(xiàn)之后,經(jīng)過了不斷的發(fā)展變化,以及 W3C 組織的標(biāo)準(zhǔn)化工作,因此目前的版本比較多,具體如下所示:

  • DOM 級(jí)別 0:1996 年,Netscape 公司的 Netscape Navigator 2.0 瀏覽器中率先引入了 JavaScript 這一腳本語(yǔ)言。開發(fā)人員可以利用 JavaScript 來操作頁(yè)面上的元素。此時(shí)的 DOM 稱為 DOM 級(jí)別 0。它只支持對(duì)頁(yè)面中的表單、鏈接和圖像進(jìn)行操作。
  • 中間 DOM:中間 DOM(Intermediate DOM)指的是 DOM 級(jí)別 0 和 DOM 級(jí)別 1 之間的一個(gè)中間版本。在這個(gè)版本中,可以通過 JavaScript 來改變頁(yè)面的樣式表。另外,頁(yè)面上更多的元素可以通過 DOM 來進(jìn)行操作。
  • DOM 級(jí)別 1:DOM 級(jí)別 1 是由 W3C 制定的 DOM 規(guī)范標(biāo)準(zhǔn),在 1998 年發(fā)布。DOM 級(jí)別 1 的規(guī)范定義了訪問和操作 HTML 頁(yè)面中元素的基本方式。
  • DOM 級(jí)別 2:DOM 級(jí)別 2 在 DOM 級(jí)別 1 的基礎(chǔ)上增加了 getElementById()方法、DOM 遍歷和范圍、名稱空間和 CSS 的支持。
  • DOM 級(jí)別 3:DOM 級(jí)別 3 在 DOM 級(jí)別 2 的基礎(chǔ)上增加了 adoptNode()textContent等方法和屬性、文檔保存和加載、文檔驗(yàn)證和 XPath 等。

本文中將重點(diǎn)介紹 DOM 級(jí)別 1 和級(jí)別 2 的部分。這些部分的內(nèi)容目前在不同瀏覽器之間的兼容性較好,而且也很常用。下面重點(diǎn)介紹 DOM 規(guī)范中的基本元素。

DOM 基本元素

對(duì)于 HTML 文檔中的基本元素,DOM 都有一個(gè)抽象的接口與它對(duì)應(yīng)。

  • 文檔(Document):文檔接口用來表示整個(gè) HTML 文檔。對(duì)文檔中其它元素和內(nèi)容的訪問和操作,都是從這個(gè)接口出發(fā)的。
  • 文檔片段(DocumentFragment):文檔片段用來表示整個(gè)文檔樹中的一個(gè)部分。
  • 節(jié)點(diǎn)(Node):節(jié)點(diǎn)接口用來表示 HTML 文檔樹中的一個(gè)節(jié)點(diǎn)。這是一個(gè)抽象的接口,在文檔樹中具體存在的都是該接口的子類型,如元素、屬性和文本節(jié)點(diǎn)等。
  • 節(jié)點(diǎn)列表(NodeList):節(jié)點(diǎn)列表表示的是節(jié)點(diǎn)的一個(gè)有序集合。它的作用類似于 Java 中的 java.util.List接口??梢酝ㄟ^節(jié)點(diǎn)在集合中的序號(hào)來獲取集合中的某個(gè)節(jié)點(diǎn)。
  • 命名節(jié)點(diǎn)映射表(NamedNodeMap):命名節(jié)點(diǎn)映射表表示的是可以根據(jù)名稱來進(jìn)行存取的節(jié)點(diǎn)集合。它的作用類似于 Java 中的 java.util.Map接口。
  • 元素(Element):元素是節(jié)點(diǎn)的一種子類型,可以包含子節(jié)點(diǎn)和屬性。
  • 屬性(Attr):屬性用來描述元素的特征。它并不是文檔樹的一部分。
  • 文本(Text):文本表示元素和屬性的文本內(nèi)容。
  • DOM 異常(DOMException):DOM 異常用來表示 DOM 操作無法執(zhí)行時(shí)的錯(cuò)誤情況。DOM 異常中定義了一系列的出錯(cuò)條件與錯(cuò)誤代碼。
  • DOM 實(shí)現(xiàn)(DOMImplementation):DOM 實(shí)現(xiàn)表示與 DOM 接口對(duì)應(yīng)的具體實(shí)現(xiàn)。

 

這里需要注意的是節(jié)點(diǎn)列表中的節(jié)點(diǎn)是動(dòng)態(tài)的,它反映的是最新的文檔結(jié)構(gòu)。比如通過 DOM API 獲得了某個(gè)元素的子節(jié)點(diǎn)列表,如果其中的某個(gè)子節(jié)點(diǎn)被刪除,此節(jié)點(diǎn)就不會(huì)出現(xiàn)在之前的節(jié)點(diǎn)列表中。

在介紹完 DOM 的基本概念之后,下面介紹如何使用 DOM 對(duì)當(dāng)前文檔樹進(jìn)行查詢。


DOM 查詢

通過 DOM 提供的 API 來對(duì)當(dāng)前文檔樹進(jìn)行查詢,是操作文檔的前提。由于文檔樹結(jié)構(gòu)可能很復(fù)雜,查詢到所需節(jié)點(diǎn)的操作有可能會(huì)比較繁瑣。這里介紹兩種方法來進(jìn)行查詢,一種是利用 DOM 規(guī)范中定義的基本 API,另外一種是使用 Dojo。下面先從基本 API 開始。

使用基本 API

使用 DOM 規(guī)范中提供的 API,就可以對(duì)文檔進(jìn)行查詢,以及在文檔中自由導(dǎo)航。下面給出一些常用的方法和屬性。

首先介紹的是兩個(gè)用來在文檔樹中快速查找元素的方法:getElementById()getElementsByTagName()。

文檔接口的 getElementById(elementId)方法是在 DOM 級(jí)別 2 中引入的。該方法的作用是在文檔中查找標(biāo)識(shí)符為 elementId的元素。如果有,則返回該元素;否則返回 null。對(duì) HTML 文檔來說,元素的標(biāo)識(shí)符是通過屬性 id來指定的。如 document.getElementById("mySpan")在當(dāng)前文檔中查找標(biāo)識(shí)符為 mySpan的元素。

文檔和元素接口的 getElementsByTagName(tagname)方法用來查找標(biāo)簽名為 tagname的子元素。該方法的返回結(jié)果是節(jié)點(diǎn)列表,其中子元素的排列順序是樹遍歷時(shí)的先序順序。通過指定 tagname的值為 *,可以匹配所有標(biāo)簽。如 document.getElementsByTagName("div")查找當(dāng)前文檔中所有的 div元素。

下面介紹在查找到單個(gè)節(jié)點(diǎn)之后,如何查找其相鄰節(jié)點(diǎn)。

在文檔樹中,每個(gè)節(jié)點(diǎn)的具體類型不盡相同。在節(jié)點(diǎn)接口中定義了屬性 nodeType用來獲取當(dāng)前節(jié)點(diǎn)的具體類型。該屬性的值是一系列預(yù)定義的常量值。屬性 nodeNamenodeValue的值也與節(jié)點(diǎn)的具體類型相關(guān)。如對(duì)于元素節(jié)點(diǎn)來說,nodeName的值是標(biāo)簽名稱,nodeValue的值是 null;對(duì)于屬性節(jié)點(diǎn)來說,nodeNamenodeValue的值分別是屬性的名稱和值;對(duì)于文本節(jié)點(diǎn)來說,nodeName的值是 #text,nodeValue的值是文本的內(nèi)容。

在訪問文檔樹的時(shí)候,一個(gè)常見的需求是訪問當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)、兄弟節(jié)點(diǎn)和子節(jié)點(diǎn)。節(jié)點(diǎn)接口中提供了相應(yīng)的屬性用來獲取這些節(jié)點(diǎn)。

  • parentNode:獲取當(dāng)前節(jié)點(diǎn)的父節(jié)點(diǎn)。除了文檔、文檔片段和屬性之外的其它節(jié)點(diǎn)都可以擁有父節(jié)點(diǎn)。
  • childNodes:獲取當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn),是一個(gè)節(jié)點(diǎn)列表。
  • hasChildNodes():該方法用來判斷當(dāng)前節(jié)點(diǎn)是否有子節(jié)點(diǎn)。
  • firstChild:獲取當(dāng)前節(jié)點(diǎn)的第一個(gè)子節(jié)點(diǎn)。如果沒有則返回 null。
  • lastChild:獲取當(dāng)前節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)。如果沒有則返回 null。
  • previousSibling:獲取出現(xiàn)在當(dāng)前節(jié)點(diǎn)正前面的兄弟節(jié)點(diǎn)。如果沒有則返回 null。
  • nextSibling:獲取出現(xiàn)在當(dāng)前節(jié)點(diǎn)正后面的兄弟節(jié)點(diǎn)。如果沒有則返回 null。
節(jié)點(diǎn)接口還提供了 attributes屬性用來獲取節(jié)點(diǎn)的屬性。對(duì)于元素節(jié)點(diǎn),返回的是一個(gè)命名節(jié)點(diǎn)映射表;對(duì)于其它類型的節(jié)點(diǎn),返回的是 null。通過屬性 ownerDocument可以獲取節(jié)點(diǎn)所在的文檔。

 

上面介紹的這些基本 API 是由瀏覽器來實(shí)現(xiàn)的。下面介紹 Dojo 提供的 dojo.query。

使用 dojo.query

使用上面提到的 DOM 規(guī)范定義的基本 API,可以完成對(duì) HTML 文檔的查詢。不過基本 API 的主要問題在于所提供的方法粒度較細(xì)。即便是滿足一些簡(jiǎn)單的查詢需求,也需要相當(dāng)多的代碼量。比如查找某個(gè) div元素下面所有的 span元素,就需要用到 getElementById()getElementsByTagName()兩個(gè)方法。而對(duì) DOM 進(jìn)行查詢又是十分常用的操作,因此開發(fā)人員需要更加方便的進(jìn)行 DOM 查詢的方法。Dojo 中提供了 dojo.query 庫(kù),用來方便的進(jìn)行 DOM 查詢。dojo.query 的基本用法是使用 CSS 3 的選擇器語(yǔ)法來選擇 HTML 文檔中的節(jié)點(diǎn)。對(duì)于復(fù)雜的查詢條件,可以用復(fù)雜的 CSS 選擇器來描述。使用 dojo.query 可以極大的降低代碼量。比如上面提到的例子,用 dojo.query 的話只需要一行代碼就足夠了:dojo.query("#myDiv span")。另外 dojo.query 使用的是 CSS 的選擇器語(yǔ)法,這對(duì)于開發(fā)人員來說并不陌生。代碼清單 1中給出了一些常用的 dojo.query 的用法。


清單 1. 常用的 dojo.query 用法
 dojo.query("#header > h1")   //ID 為 header 的元素的直接子節(jié)點(diǎn)中的 h3 元素            dojo.query("span[title^='test']")  // 屬性 title 以字符串 test 開頭的 span 元素            dojo.query("div[id$='widget']") // 屬性 id 以字符串 widget 結(jié)尾的 div 元素            dojo.query("input[name*='value']")  // 屬性 name 包含子串 value 的 input 元素            dojo.query("#myDiv, .error") // 組合查詢,結(jié)果中包含 ID 為 myDiv 的元素和 CSS 類為 error 的元素            dojo.query(".message.info") // 同時(shí)包含了 CSS 類 message 和 info 的元素,注意兩個(gè)類之間不包含空格            dojo.query("tr:nth-child(even)") // 出現(xiàn)在父節(jié)點(diǎn)的偶數(shù)位置的 tr 元素            dojo.query("input[type=checkbox]:checked") // 所有選中狀態(tài)的復(fù)選框            dojo.query(".message:not(:nth-child(odd))") // 嵌套子查詢,選中包含 CSS 類 message,            //并且不出現(xiàn)在父節(jié)點(diǎn)的奇數(shù)位置的元素            

dojo.query方法除了第一個(gè)必須的參數(shù)用來表示所用的選擇器語(yǔ)法之外,還有一個(gè)可選的參數(shù)用來指定查詢的范圍,可以是一個(gè) ID 或是元素。如果傳入該參數(shù),則查詢結(jié)果中只包含該元素的子節(jié)點(diǎn)。默認(rèn)的查詢范圍是整個(gè)文檔樹。如 dojo.query("span.info", "myDiv")只在 ID 為 myDiv的元素的子節(jié)點(diǎn)中查詢包含 CSS 類 info的 span 元素。熟練使用 dojo.query 的前提條件是對(duì) CSS 3 規(guī)范定義的選擇器語(yǔ)法比較熟悉。關(guān)于 CSS 3 選擇器語(yǔ)法的更多信息,請(qǐng)見 參考資料。

dojo.query 的另外一個(gè)強(qiáng)大功能是可以對(duì)選擇出來的節(jié)點(diǎn)進(jìn)行統(tǒng)一處理。通過方法級(jí)聯(lián)還可以寫出非常簡(jiǎn)潔的代碼。下面的章節(jié)中將會(huì)詳細(xì)介紹 dojo.query 的這一能力。

在介紹完使用基本 API 和 dojo.query進(jìn)行 DOM 查詢之后,下面介紹如何進(jìn)行 DOM 操作。


DOM 操作

在通過上面介紹的基本 API 或是 dojo.query 查詢到所需的節(jié)點(diǎn)之后,下面就可以對(duì)這些節(jié)點(diǎn)進(jìn)行操作了。查詢是為操作服務(wù)的。對(duì) DOM 的操作包括對(duì)節(jié)點(diǎn)的創(chuàng)建、插入、更新和刪除操作。下面將具體介紹如何使用基本 API 和 Dojo 來完成 DOM 操作。

使用基本 API

創(chuàng)建新的節(jié)點(diǎn)的統(tǒng)一入口是定義在文檔接口中的一系列方法。這些方法都以 create開頭。常用的方法有 createElement(tagName)用來創(chuàng)建一個(gè)標(biāo)簽名為 tagName的元素;createTextNode(data)用來創(chuàng)建一個(gè)內(nèi)容為 data的文本節(jié)點(diǎn);createAttribute(name)用來創(chuàng)建一個(gè)名稱為 name的屬性節(jié)點(diǎn);createDocumentFragment()用來創(chuàng)建一個(gè)文檔片段。

創(chuàng)建出新的節(jié)點(diǎn)之后,就需要將其插入到當(dāng)前文檔樹中。節(jié)點(diǎn)接口定義了兩個(gè)方法用來完成插入的操作。

  • appendChild(newChild):把節(jié)點(diǎn) newChild添加到當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)列表中。
  • insertBefore(newChild, refChild):與 appendChild()類似的是都是把節(jié)點(diǎn) newChild添加到當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn)列表中,不同的是可以通過參數(shù) refChild來指定位置。節(jié)點(diǎn) newChild出現(xiàn)在節(jié)點(diǎn) refChild的正前面。

 

節(jié)點(diǎn)接口的 replaceChild(newChild, oldChild)方法用來將當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn) oldChild替換成新的節(jié)點(diǎn) newChild。方法 removeChild(oldChild)用來刪除當(dāng)前節(jié)點(diǎn)的子節(jié)點(diǎn) oldChild

對(duì)于元素節(jié)點(diǎn)來說,可以對(duì)其屬性進(jìn)行操作。方法 setAttribute(name, value)用來設(shè)置名為 name的屬性的值為 value。方法 removeAttribute(name)用來刪除名為 name的屬性。

如果一個(gè)節(jié)點(diǎn)已經(jīng)在文檔樹中存在,通過上面提到的 appendChild()、insertBefore()replaceChild()方法改變其在文檔樹中的位置的時(shí)候,該節(jié)點(diǎn)會(huì)首先被從文檔樹中刪除,然后再被插入到新的位置中。在插入文檔片段的時(shí)候,文檔片段本身并不會(huì)被插入,只有其子節(jié)點(diǎn)被插入到文檔樹中。

使用 Dojo

Dojo 也提供了一系列的 API 用來執(zhí)行 DOM 操作。下面介紹常用的方法。

dojo.place(node, refNode, position)方法用來插入節(jié)點(diǎn)到文檔樹中的指定位置。該方法的參數(shù) node用來指定待插入元素的 ID 或引用;refNode用來指定插入元素時(shí)的參照元素;position用來指定相對(duì)于參照元素的位置,可選的值有 before、afterreplace、only、firstlast,分別表示在參照元素之前、之后、替換掉參照元素、替換掉參照元素的全部子節(jié)點(diǎn)、作為參照元素的第一個(gè)子元素,以及作為參照元素的最后一個(gè)子元素。也可以傳入表示在參照元素的子節(jié)點(diǎn)中的序號(hào)位置。last是默認(rèn)值,其作用相當(dāng)于之前介紹的 appendChild()方法。如果該方法的第一個(gè)參數(shù)是以“<”開頭的字符串,則創(chuàng)建一個(gè)以該字符串為內(nèi)容的文檔片段并插入此片段。

Dojo 提供了 3 個(gè)與元素的屬性相關(guān)的方法。dojo.attr(node, name, value)用來獲取或設(shè)置元素的屬性。該方法的參數(shù) node用來指定元素的 ID 或是引用;name用來指定要獲取或設(shè)置的屬性的名稱,也可以是一個(gè)包含“屬性 / 值”名值對(duì)的 JSON 對(duì)象;value用來指定要設(shè)置的屬性的值。傳入兩個(gè)參數(shù)可以是獲取單個(gè)屬性的值,也可以是設(shè)置一組屬性的值。如 dojo.attr(node, "title")用來獲取屬性 title的值,dojo.attr(node, {"title" : "My Title", "tabIndex" : 1})用來同時(shí)設(shè)置屬性 titletabIndex的值。傳入三個(gè)參數(shù)用來設(shè)置單個(gè)屬性的值,如 dojo.attr(node, "name", "username")用來設(shè)置屬性 name的值。在設(shè)置屬性的時(shí)候,可以傳入方法作為參數(shù)用來綁定事件處理。dojo.hasAttr(node, name)用來判斷元素是否有名為 name的屬性。dojo.removeAttr(node, name)用來刪除元素的名為 name的屬性。

dojo.create(tag, attrs, refNode, pos)方法用來創(chuàng)建新元素,并且可以指定元素的屬性和在文檔樹中的位置。該方法可以有 4 個(gè)參數(shù),只有第一個(gè)表示標(biāo)簽名的參數(shù) tag是必須的。第二個(gè)參數(shù) attrs指定元素的屬性,實(shí)現(xiàn)時(shí)使用 dojo.attr()方法。最后兩個(gè)參數(shù)指定新創(chuàng)建的元素在文檔樹中的位置,實(shí)現(xiàn)時(shí)使用 dojo.place()方法。

前面在介紹 dojo.query 的時(shí)候提到可以對(duì)選擇出來的節(jié)點(diǎn)進(jìn)行處理,下面進(jìn)行具體介紹。dojo.query()方法返回的結(jié)果是 dojo.NodeList對(duì)象。dojo.NodeList繼承自 JavaScript 中的數(shù)組類型,并添加了很多實(shí)用的方法,可以很方便的對(duì)選擇出來的節(jié)點(diǎn)集合進(jìn)行操作。其中的很多方法的返回結(jié)果也是 dojo.NodeList對(duì)象。這樣多個(gè)方法的調(diào)用就可以級(jí)聯(lián)起來,使得代碼更加簡(jiǎn)單。在這一點(diǎn)上,dojo.query 的用法與 jQuery 比較類似。具體的級(jí)聯(lián)用法見 dojo.query 級(jí)聯(lián)一節(jié)。

dojo.NodeList中包含了與數(shù)組元素處理、DOM 操作、CSS 樣式處理和事件綁定相關(guān)的很多方法,下面具體介紹其中的實(shí)用方法,如下所示。

  • forEach()、map()、filter()slice()、splice()、indexOf()、lastIndexOf()every()some():這些是對(duì)節(jié)點(diǎn)數(shù)組本身進(jìn)行操作的方法。dojo.NodeList的這些方法與操作數(shù)組的對(duì)應(yīng)方法的含義相同,只是操作的對(duì)象被隱式指定為當(dāng)前的節(jié)點(diǎn)數(shù)組。
  • attr()removeAttr():這兩個(gè)是用來操作元素屬性的方法,可以為節(jié)點(diǎn)數(shù)組中每個(gè)元素設(shè)置屬性值或刪除屬性值。如 dojo.query("a").attr("target", "_blank")查找頁(yè)面中所有的 a元素,并把其屬性 target的值設(shè)成 _blank。
  • style()、addClass()、removeClass()toggleClass():這些方法用來設(shè)置節(jié)點(diǎn)數(shù)組中每個(gè)元素的樣式和 CSS 類。如 dojo.query("p").style("fontSize", "1.2em")把頁(yè)面上所有的 p元素的字體大小設(shè)成 1.2em。
  • append()prepend()、after()before():這四個(gè)方法為節(jié)點(diǎn)數(shù)組中的每個(gè)元素添加內(nèi)容,只是新添加內(nèi)容的位置不同,分別位于節(jié)點(diǎn)的最后一個(gè)子節(jié)點(diǎn)、第一個(gè)子節(jié)點(diǎn)、之后和之前。這四個(gè)方法的參數(shù)可以是 HTML 字符串、DOM 節(jié)點(diǎn)引用和 dojo.NodeList對(duì)象。如 dojo.query("p").after("<span>Hello</span>")在每個(gè) p 元素之后添加一個(gè)新的 span 元素。
  • appendTo()、prependTo()insertBefore()insertAfter():這四個(gè)方法與上面四個(gè)方法是分別對(duì)應(yīng)的,不同的是其參數(shù)是一個(gè) dojo.query 查詢字符串,節(jié)點(diǎn)數(shù)組中的元素被添加到由該查詢指定的節(jié)點(diǎn)的對(duì)應(yīng)位置上??梢钥闯墒巧厦嫠膫€(gè)方法的逆操作。如 dojo.query("span.message").appendTo("#main")把包含 CSS 類 message的 span 元素添加為 ID 為 main的元素的最后一個(gè)子節(jié)點(diǎn)。
  • wrap()wrapAll()wrapInner():這三個(gè)方法用來包裝節(jié)點(diǎn)數(shù)組中的元素。wrap()wrapInner()都是對(duì)節(jié)點(diǎn)中的每個(gè)元素添加包裝,不同的是前者包裝的是元素本身,而后者包裝的是元素的子節(jié)點(diǎn)。wrapAll()是包裝的節(jié)點(diǎn)數(shù)組中的全部元素。代碼清單 2中給出了這三個(gè)方法的用法。
  • children()、parent()、next()prev():這四個(gè)方法用來查詢節(jié)點(diǎn)數(shù)組中元素的子節(jié)點(diǎn)、父節(jié)點(diǎn)、后面和前面的相鄰節(jié)點(diǎn)。這些方法都接受一個(gè)查詢條件作為參數(shù)來進(jìn)一步過濾結(jié)果。如 dojo.query("#myDiv").chidren(".message")查詢 ID 為 myDiv的元素的包含 CSS 類 message的子節(jié)點(diǎn)。

 


清單 2. wrap()、wrapAll() 和 wrapInner() 的用法
 // 原始的 HTML 文檔片段            <div id="myDiv">            <span class="item">            <span class="title">Item 1</span>            </span>            <span class="item">            <span class="title">Item 2</span>            </span>            </div>            // 執(zhí)行 dojo.query(".item").wrap("<div class='item-container'></div>") 之后的結(jié)果            <div id="myDiv">            <div class="item-container">            <span class="item">            <span class="title">Item 1</span>            </span>            </div>            <div class="item-container">            <span class="item">            <span class="title">Item 1</span>            </span>            </div>            </div>            // 執(zhí)行 dojo.query(".item").wrapAll("<div class='items'></div>") 之后的結(jié)果            <div id="myDiv">            <div class="items">            <span class="item">            <span class="title">Item 1</span>            </span>            <span class="item">            <span class="title">Item 1</span>            </span>            </div>            </div>            // 執(zhí)行 dojo.query(".item").wrapInner("<div class='item-inner'></div>") 之后的結(jié)果            <div id="myDiv">            <span class="item">            <div class="item-inner">            <span class="title">Item 1</span>            </div>            </span>            <span class="item">            <div class="item-inner">            <span class="title">Item 1</span>            </div>            </span>            </div>   

dojo.query 級(jí)聯(lián)

dojo.query方法返回的是 dojo.NodeList對(duì)象,而 dojo.NodeList對(duì)象的絕大多數(shù)方法返回的也是 dojo.NodeList對(duì)象。這樣的話,對(duì) dojo.NodeList的多個(gè)方法可以級(jí)聯(lián)起來,使得寫出來的代碼更加簡(jiǎn)潔。在使用級(jí)聯(lián)的時(shí)候需要注意 dojo.NodeList中包含的節(jié)點(diǎn)的變化,以免在錯(cuò)誤的節(jié)點(diǎn)上面進(jìn)行操作。使用 end()方法可以取消上一次對(duì) dojo.NodeList的操作所造成的節(jié)點(diǎn)數(shù)組的改變。代碼清單 3給出了 dojo.query 級(jí)聯(lián)的示例。


清單 3. dojo.query 級(jí)聯(lián)示例
 // 原始的 HTML 片段            <div>            <div class="item">            <div>Item 1</div>            <div>Item 2</div>            </div>            </div>            //JavaScript 代碼            dojo.query(".item").children().addClass("subItem").end()            .parent().addClass("itemContainer");            // 更新之后的 HTML 片段            <div class="itemContainer">            <div class="item">            <div class="subItem">Item 1</div>            <div class="subItem">Item 2</div>            </div>            </div>

代碼清單 3所示,dojo.query(".item")的節(jié)點(diǎn)數(shù)組中包含的是包含 CSS 類 item的元素,調(diào)用 children()之后,節(jié)點(diǎn)數(shù)組變?yōu)樯鲜鲈氐淖釉?,即兩個(gè) div元素;addClass()對(duì)這兩個(gè) div元素進(jìn)行操作;接下來的 end()方法則把節(jié)點(diǎn)數(shù)組還原成 children()被調(diào)用之前的狀態(tài);接下來的 parent()選擇的是包含 CSS 類 item的元素的父元素,addClass()對(duì)此父元素進(jìn)行操作??梢钥吹?,通過 end()方法的使用可以在一條語(yǔ)句中執(zhí)行非常復(fù)雜的操作。不過從代碼的可讀性來說,一條語(yǔ)句中最好不要包含多個(gè) end()

在介紹完使用 DOM 基本 API 和 Dojo 進(jìn)行 DOM 操作之后,下面介紹在 Ajax 應(yīng)用中使用 DOM 的相關(guān)內(nèi)容。


在 Ajax 應(yīng)用中使用 DOM

DOM 查詢和操作在 Ajax 應(yīng)用中是非?;镜摹Mㄟ^ DOM 操作,可以動(dòng)態(tài)的對(duì)頁(yè)面進(jìn)行局部修改。這種“局部刷新”的用戶體驗(yàn),也是 Ajax 應(yīng)用相對(duì)于傳統(tǒng) Web 應(yīng)用的重要優(yōu)勢(shì)之一。一般來說,對(duì)頁(yè)面的局部修改由用戶的操作來觸發(fā)。用戶通過鼠標(biāo)和鍵盤觸發(fā)相應(yīng)的瀏覽器事件,在事件的響應(yīng)方法中進(jìn)行 DOM 查詢和操作。另外一種可能的觸發(fā)條件是瀏覽器中的定時(shí)器機(jī)制。一些局部修改可以完全在瀏覽器端來實(shí)現(xiàn),而另外一些局部修改則需要服務(wù)器端的支持。一般來說,在 Ajax 應(yīng)用中使用 DOM 有下面三種實(shí)現(xiàn)模式。

  • 服務(wù)器端返回?cái)?shù)據(jù),瀏覽器端使用 DOM 操作:在這種模式下,服務(wù)器端返回的只是數(shù)據(jù)本身,并不包含展示相關(guān)的內(nèi)容。瀏覽器端通過 XMLHTTPRequest 請(qǐng)求獲取到數(shù)據(jù)之后,通過 DOM 操作來生成所需的頁(yè)面片段,并添加到當(dāng)前頁(yè)面中。
  • 服務(wù)器端返回 HTML 片段,瀏覽器端簡(jiǎn)單顯示:在這種模式下,服務(wù)器端通過模板技術(shù),如 JSP™、Apache Velocity、等生成 HTML 片段,返回給瀏覽器。瀏覽器只需要用獲取的 HTML 片段更新當(dāng)前頁(yè)面即可。
  • 服務(wù)器端返回?cái)?shù)據(jù),瀏覽器端使用模板:在這種模式下,服務(wù)器端返回的只是數(shù)據(jù)。瀏覽器端不是通過 DOM 操作來生成 HTML 片段,而是通過模板來進(jìn)行生成。

這三種模式的區(qū)別在于兩點(diǎn):服務(wù)器端返回?cái)?shù)據(jù)還是展示,瀏覽器端使用 DOM 操作還是模板。對(duì)于第一點(diǎn),服務(wù)器端返回?cái)?shù)據(jù)的好處是傳輸量較小、和客戶端的耦合較松散以及較容易支持除瀏覽器之外的其它客戶端。返回?cái)?shù)據(jù)的格式常見的有 XML 和 JSON。不足之處在于在瀏覽器端有比較多的邏輯來生成 HTML 片段。對(duì)于第二點(diǎn),DOM 操作的好處是簡(jiǎn)單易用,使用起來比較直接。不足之處在于代碼編寫比較復(fù)雜和冗長(zhǎng)。而使用模板的話,所生成的 HTML 片段的結(jié)構(gòu)可以從模板中很直觀的看到,修改起來比較方便。但是也增加了額外的復(fù)雜度。代碼清單 4給出了服務(wù)器端返回?cái)?shù)據(jù),瀏覽器端使用 DOM 操作的示例。


清單 4. 服務(wù)器端返回?cái)?shù)據(jù),瀏覽器端使用 DOM 操作
 dojo.xhrGet({            url : "/posts",            load : function(data) {            var container = dojo.byId("posts");            for (var i = 0, n = data.length; i < n; i++) {            var post = data[i];            var postNode = dojo.create("div", {            className : "post"            }, container);            dojo.create("div", {            className : "title",            innerHTML : post.title            }, postNode);            dojo.create("div", {            className : "content",            innerHTML : post.content            }, postNode);            }            },            error : function() {            dojo.html.set(dojo.byId("posts"), "獲取文章出錯(cuò)。");            }            });   

代碼清單 4所示,服務(wù)器端返回的是 JSON 格式的數(shù)據(jù),在瀏覽器端使用 dojo.create()來執(zhí)行 DOM 操作。代碼清單 5給出了服務(wù)器端返回?cái)?shù)據(jù),在瀏覽器端使用模板技術(shù)進(jìn)行 DOM 操作的示例。


清單 5. 服務(wù)器端返回?cái)?shù)據(jù),瀏覽器端使用模板
 var template = "<div class="post"><div class="title">${title}</div>"            + "<div class="content">${content}</div></div>";            dojo.xhrGet({            url : "/posts",            load : function(data) {            var container = dojo.byId("posts");            for (var i = 0, n = data.length; i < n; i++) {            var node = dojo.create("div", {            innerHTML : dojo.string.substitute(template, data[i]);            });            container.appendChild(node.firstChild);            }            },            error : function() {            dojo.html.set(dojo.byId("posts"), "獲取文章出錯(cuò)。");            }            });   

代碼清單 5所示,template中包含的就是 HTML 模板,從服務(wù)器端獲得數(shù)據(jù)之后,通過 dojo.string.substitute()把數(shù)據(jù)應(yīng)用在模板上,從而得到所需的 HTML 片段內(nèi)容。

在介紹與在 Ajax 應(yīng)用中使用 DOM 相關(guān)的內(nèi)容之后,下面介紹與 DOM 查詢和操作相關(guān)的一些高級(jí)話題。


高級(jí)話題

下面討論幾個(gè)與 DOM 查詢和操作相關(guān)的高級(jí)話題。首先從 DOM 操作的性能開始。

性能

在 Ajax 應(yīng)用中,性能是一個(gè)很重要的問題。由于 DOM 操作 Ajax 應(yīng)用中非常普遍,提升 DOM 操作的性能對(duì)于整體的性能有很大影響。下面介紹一些好的實(shí)踐。

  • 使用文檔片段:文檔片段是一個(gè)輕量級(jí)的文檔對(duì)象,可以用來包含其它節(jié)點(diǎn)。當(dāng)文檔片段被插入到文檔樹中的時(shí)候,其本身并不會(huì)被插入,而只有其子節(jié)點(diǎn)被插入。一個(gè)常見的提高 DOM 操作性能的做法是利用文檔片段來插入新創(chuàng)建的節(jié)點(diǎn)。首先創(chuàng)建一個(gè)文檔片段,再把新創(chuàng)建的節(jié)點(diǎn)插入到文檔片段中,再把該文檔片段插入到文檔樹中。這樣做的好處是可以減少頁(yè)面的重新排列(reflow)。每次對(duì)文檔樹的 DOM 操作都會(huì)導(dǎo)致頁(yè)面重新排列,從而影響 Web 應(yīng)用的性能。有兩種情況下的 DOM 操作不會(huì)導(dǎo)致頁(yè)面重新排列:一種是對(duì)不可見元素(CSS 樣式 display的值是 none)的操作,另外一種是不在當(dāng)前文檔樹中的元素。由于文檔片段不在當(dāng)前文檔樹中,對(duì)它的修改并不會(huì)造成頁(yè)面的重新排列。
  • 使用 innerHTML:這種做法是通過字符串拼接來構(gòu)造 HTML 文檔,再通過設(shè)置元素的 innerHTML來修改其內(nèi)容。使用 innerHTML比一般的 DOM 操作要快。
  • 使用 cloneNode():當(dāng)需要?jiǎng)?chuàng)建多個(gè)結(jié)構(gòu)相同的元素時(shí),比較好的辦法是首先創(chuàng)建出一個(gè)元素作為模板,然后用 cloneNode()方法復(fù)制出其它的元素。這樣比逐個(gè)創(chuàng)建每個(gè)元素速度要快。需要注意的是,通過 cloneNode()復(fù)制出來的元素會(huì)丟失原來綁定在其上的事件處理方法,需要重新進(jìn)行事件綁定。

 

代碼清單 6中給出了使用文檔片段和 cloneNode()來提高 DOM 操作性能的示例。


清單 6. 高效 DOM 操作示例
 var df = document.createDocumentFragment();            for (var i = 0; i < 10; i++) {            dojo.create("div", {            innerHTML : "node " + i            }, df);            }            var node = dojo.byId("myDiv");            for (var i = 0; i < 10; i++) {            node.appendChild(df.cloneNode(true));            }

瀏覽器兼容性

由于 DOM 規(guī)范的版本較多,時(shí)間跨度長(zhǎng),不同瀏覽器對(duì) DOM 規(guī)范的支持程度也不盡相同。目前來說,主流瀏覽器對(duì) DOM 規(guī)范級(jí)別 1 的全部以及級(jí)別 2 的核心部分,都有著不錯(cuò)的支持。在 Ajax 應(yīng)用中,應(yīng)該盡可能的使用這部分 DOM API。使用 JavaScript 庫(kù)也能減少兼容性問題。關(guān)于 DOM 的瀏覽器兼容性問題的細(xì)節(jié),見 參考資料。

dojo.NodeList 插件

前面提到 dojo.NodeList提供了很多方法用來對(duì)查詢到的節(jié)點(diǎn)數(shù)組進(jìn)行操作。開發(fā)人員可以通過擴(kuò)展 dojo.NodeList的方式來提供更加豐富的功能。這種擴(kuò)展方式類似于 jQuery 中的插件機(jī)制。下面通過開發(fā)一個(gè)插件來進(jìn)行說明。該插件實(shí)現(xiàn)的功能是點(diǎn)擊標(biāo)題欄可以控制內(nèi)容的展開和收縮。代碼清單 7給出了示例插件的 HTML 和 JavaScript 代碼。


清單 7. dojo.NodeList 插件示例
 //HTML 代碼片段            <div>            <div class="toggler">Header 1</div>            <div>Body 1</div>            </div>            //JavaScript 代碼            dojo.NodeList.prototype.toggler = function(options) {            var opts = dojo.mixin({}, dojo.NodeList.prototype.toggler.defaults, options);            var collapsedOnLoad = opts.collapsedOnLoad;            return this.forEach(function(node) {            dojo.connect(node, "onclick", function() {            var collapsed = dojo.attr(node, "collapsed") == "true";            dojo.query(node).next().style("display", collapsed ? "" : "none");            dojo.attr(node, "collapsed", (!collapsed).toString());            });            if (collapsedOnLoad) {            dojo.attr(node, "collapsed", "true");            dojo.query(node).next().style("display", "none");            }            });            };            dojo.NodeList.prototype.toggler.defaults = {            collapsedOnLoad : true            };            dojo.addOnLoad(function() {            dojo.query(".toggler").toggler();            });

代碼清單 7中,首先為 dojo.NodeList添加新的方法 toggler()。該方法可以對(duì)節(jié)點(diǎn)數(shù)組中的每個(gè)節(jié)點(diǎn)添加行為,使得該節(jié)點(diǎn)可以控制其相鄰的下一個(gè)節(jié)點(diǎn)是否顯示。具體的做法是通過 dojo.connect進(jìn)行事件的綁定,當(dāng)點(diǎn)擊該節(jié)點(diǎn)的時(shí)候,根據(jù)節(jié)點(diǎn)的自定義屬性 collapsed的值來確定其下一個(gè)節(jié)點(diǎn)的 CSS 樣式 display的值。在使用的時(shí)候,只需要通過 dojo.query()查詢到所需的節(jié)點(diǎn),再調(diào)用此方法即可。

dojo.behavior

dojo.behavior允許以聲明的方式為頁(yè)面上的特定元素添加行為。進(jìn)行聲明的時(shí)候,只需要說明元素所滿足的模式,以及針對(duì)這些元素所應(yīng)用的行為即可。聲明模式的時(shí)候使用的是與 dojo.query相同的 CSS 3 選擇器語(yǔ)法。對(duì)于每種模式,可以聲明多種不同的行為。對(duì)于每種行為,需要聲明其觸發(fā)的條件,以及對(duì)應(yīng)的動(dòng)作。觸發(fā)的條件一般有兩種:一種是找到匹配模式的元素,用 found來聲明;另外一種則是元素上的各種事件,如 onclickonmouseoveronmouseout等。第一種是默認(rèn)的觸發(fā)條件。對(duì)應(yīng)的動(dòng)作一般有兩種:一種是調(diào)用 JavaScript 方法,另外一種是用 dojo.publish來發(fā)布某種主題的通知。在使用 dojo.behavior的時(shí)候,首先通過 dojo.behavior.add()來添加聲明,再通過 dojo.behavior.apply()來應(yīng)用這些聲明。這些聲明的應(yīng)用是增量式的,同樣的聲明對(duì)于同樣的節(jié)點(diǎn)不會(huì)重復(fù)應(yīng)用。新添加的節(jié)點(diǎn)會(huì)應(yīng)用當(dāng)前所有的行為聲明。在頁(yè)面加載完成之后,dojo.behavior.apply()會(huì)被自動(dòng)調(diào)用。

下面通過一個(gè)具體的實(shí)例來進(jìn)行說明。頁(yè)面中文本的截?cái)嗍且粋€(gè)很常見的操作。當(dāng)元素的大小不足以全部顯示其文本的時(shí)候,文本的一部分會(huì)被截?cái)?。一種比較好的做法是在被截?cái)嗟奈谋竞竺婕由?...來提醒用戶。代碼清單 8中給出了用 dojo.behavior實(shí)現(xiàn)文本截?cái)嗟拇a。


清單 8. dojo.behavior 示例
 //HTML 代碼            <span class="label" maxLength="5">This label is very long.</span>            //JavaScript 代碼            dojo.behavior.add({            ".label[maxLength]" : {            found :  function(node) {            var text = node.innerHTML,            maxLength = parseInt(dojo.attr(node, "maxLength")),            truncatedText = text.length > maxLength ?            text.substring(0, maxLength) + "..." : text;            dojo.attr(node, "title", text);            node.innerHTML = truncatedText;            }            }            });

代碼清單 8中的行為聲明的含義是如果遇到包含 CSS 類 label和屬性 maxLength的元素,需要檢查其包含文本的長(zhǎng)度是否超過屬性 maxLength指定的長(zhǎng)度。如果超過的話則進(jìn)行截?cái)唷?/p>


總結(jié)

DOM 查詢和操作在 Ajax 應(yīng)用開發(fā)中十分常用。簡(jiǎn)潔高效的操作 DOM,是開發(fā)一個(gè)良好 Ajax 應(yīng)用的基礎(chǔ)。本文首先介紹了 DOM 的基本概念,接著介紹了如何分別利用 DOM 規(guī)范定義的基本 API 和 Dojo 來進(jìn)行 DOM 查詢和操作。最后討論了 DOM 操作的性能、dojo.NodeList 插件和 dojo.behavior 等高級(jí)話題。通過這些內(nèi)容的介紹,可以對(duì) Ajax 應(yīng)用中 DOM 查詢和操作有更深入的了解。


聲明

本人所發(fā)表的內(nèi)容僅為個(gè)人觀點(diǎn),不代表 IBM 公司立場(chǎng)、戰(zhàn)略和觀點(diǎn)。



下載

描述 名字 大小 下載方法
本文用到的 HTML 和 JavaScript 代碼示例1 sample.zip 4KB HTTP

關(guān)于下載方法的信息

注意:

  1. 包含 dojo.query、dojo.NodeList 和 dojo.behavior 的示例代碼。

參考資料

學(xué)習(xí)

討論

關(guān)于作者

成富任職于 IBM 中國(guó)軟件開發(fā)中心,目前在 Lotus 部門從事 IBM Mashup Center 的開發(fā)工作。他畢業(yè)于北京大學(xué)信息科學(xué)技術(shù)學(xué)院,獲得計(jì)算機(jī)軟件與理論專業(yè)碩士學(xué)位。他的個(gè)人網(wǎng)站是 http://www.cheng-fu.com

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
理解XML DOM樹結(jié)構(gòu)
HTML DOM Element 對(duì)象
javascript快速入門15
什么是DOM?DOM和JavaScript的關(guān)系 - PPP - Javascript/A...
Java程序員從笨鳥到菜鳥之(二十六)XML之DOM和SAX解析
DOM解析
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服