国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
掌握 Ajax,第 5 部分: 操縱 DOM

2006 年 4 月 27 日

上一篇中 Brett 介紹了文檔對象模型(DOM),它的元素在幕后定義了 Web 頁面。這一期文章中他將進一步探討 DOM。了解如何創(chuàng)建、刪除和修改 DOM 樹的各個部分,了解如何實現(xiàn)網(wǎng)頁的即時更新!

如果閱讀過本系列的 上一篇文章,那么您就非常清楚當 Web 瀏覽器顯示網(wǎng)頁時幕后發(fā)生的一切了。前面已經(jīng)提到,當 HTML 或為頁面定義的 CSS 發(fā)送給 Web 瀏覽器時,網(wǎng)頁被從文本轉(zhuǎn)化成對象模型。無論代碼簡單或復雜,集中到一個文件還是分散到多個文件,都是如此。然后瀏覽器直接使用對象模型而不是您提供的文本文件。瀏覽器使用的模型稱為文檔對象模型(Document Object Model,DOM)。它連接表示文檔中元素、屬性和文本的對象。HTML 和 CSS 中所有的樣式、值、甚至大部分空格都合并到該對象模型中。給定網(wǎng)頁的具體模型稱為該頁面的 DOM 樹

了解什么是 DOM 樹,以及知道它如何表示 HTML 和 CSS 僅僅是控制 Web 頁面的第一步。接下來還需要了解如何處理 Web 頁面的 DOM 樹。比方說,如果向 DOM 樹中增加一個元素,這個元素就會立即出現(xiàn)在用戶的 Web 瀏覽器中 —— 不需要重新加載頁面。從 DOM 樹中刪除一些文本,那些文本就會從用戶屏幕上消失??梢酝ㄟ^ DOM 修改用戶界面或者與用戶界面交互,這樣就提供了很強的編程能力和靈活性。一旦學會了如何處理 DOM 樹,您就向?qū)崿F(xiàn)豐富的、交互式動態(tài)網(wǎng)站邁出了一大步。

注意,下面的討論以上一篇文章 “利用 DOM 進行 Web 響應(yīng)” 為基礎(chǔ),如果沒有閱讀過那一期,請在繼續(xù)閱讀之前首先閱讀上一篇文章。

首字母縮寫的拼讀問題

從很多方面來說,文檔對象模型應(yīng)該被稱為文檔節(jié)點模型(Document Node Model,DNM)。當然,大多數(shù)人不知道節(jié)點 一詞的含義,而且 “DNM” 也不像 “DOM” 那么容易拼讀,所以很容易理解 W3C 為何選擇了 DOM。

跨瀏覽器、跨語言

文檔對象模型是一種 W3C 標準(鏈接參見 參考資料)。因此,所有現(xiàn)代 Web 瀏覽器都支持 DOM —— 至少在一定程度上支持。雖然不同的瀏覽器有一些區(qū)別,但如果使用 DOM 核心功能并注意少數(shù)特殊情況和例外,DOM 代碼就能以同樣的方式用于任何瀏覽器。修改 Opera 網(wǎng)頁的代碼同樣能用于 Apple‘s Safari?、Firefox?、Microsoft? Internet Explorer? 和 Mozilla?。

DOM 也是一種跨語言 的規(guī)范,換句話說,大多數(shù)主流編程語言都能使用它。W3C 為 DOM 定義了幾種語言綁定。一種語言綁定就是為特定語言定義的讓您使用 DOM 的 API。比如,可以使用為 C、Java 和 JavaScript 定義的 DOM 語言綁定。因此可以從這些語言中使用 DOM。還有幾種用于其他語言的語言綁定,盡管很多是由 W3C 以外的第三方定義的。

本系列文章主要討論 JavaScript 的 DOM 綁定。這是因為多數(shù)異步應(yīng)用程序開發(fā)都需要編寫在 Web 瀏覽器中運行的 JavaScript 代碼。使用 JavaScript 和 DOM 可以即時修改用戶界面、響應(yīng)用戶事件和輸入等等 —— 使用的完全是標準的 JavaScript。

總之,建議您也嘗試一下其他語言中的 DOM 綁定。比如,使用 Java 語言綁定不僅能處理 HTML 還可處理 XML,這些內(nèi)容將在以后的文章中討論。因此本文介紹的技術(shù)還可用于 HTML 之外的其他語言,客戶端 JavaScript 之外的其他環(huán)境。





回頁首


節(jié)點的概念

節(jié)點是 DOM 中最基本的對象類型。實際上,您將在本文中看到,基本上 DOM 定義的其他所有對象都是節(jié)點對象的擴展。但是在深入分析語義之前,必須了解節(jié)點所代表的概念,然后再學習節(jié)點的具體屬性和方法就非常簡單了。

在 DOM 樹中,基本上一切都是節(jié)點。每個元素在最底層上都是 DOM 樹中的節(jié)點。每個屬性都是節(jié)點。每段文本都是節(jié)點。甚至注釋、特殊字符(如版權(quán)符號 ?)、DOCTYPE 聲明(如果 HTML 或者 XHTML 中有的話)全都是節(jié)點。因此在討論這些具體的類型之前必須清楚地把握什么是節(jié)點。

節(jié)點是……

用最簡單的話說,DOM 樹中的任何事物都是節(jié)點 。之所以用 “事物” 這個模糊的字眼,是因為只能明確到這個程度。比如 HTML 中的元素(如 img)和 HTML 中的文本片段(如 “Scroll down for more details”)沒有多少明顯的相似之處。但這是因為您考慮的可能是每種類型的功能,關(guān)注的是它們的不同點。

但是如果從另一個角度觀察,DOM 樹中的每個元素和每段文本都有一個父親,這個父節(jié)點可能是另一個元素(比如嵌套在 p 元素中的 img)的孩子,或者 DOM 樹中的頂層元素(這是每個文檔中都出現(xiàn)一次的特殊情況,即使用 html 元素的地方)。另外,元素和文本都有一個類型。顯然,元素的類型就是元素,文本的類型就是文本。每個節(jié)點還有某種定義明確的結(jié)構(gòu):下面還有節(jié)點(如子元素)嗎?有兄弟節(jié)點(與元素或文本 “相鄰的” 節(jié)點)嗎?每個節(jié)點屬于哪個文檔?

顯然,大部分內(nèi)容聽起來很抽象。實際上,說一個元素的類型是元素似乎有點冒傻氣。但是要真正認識到將節(jié)點作為通用對象類型的價值,必須抽象一點來思考。

通用節(jié)點類型

DOM 代碼中最常用的任務(wù)就是在頁面的 DOM 樹中導航。比方說,可以通過其 “id” 屬性定位一個 form,然后開始處理那個 form 中內(nèi)嵌的元素和文本。其中可能包含文字說明、輸入字段的標簽、真正的 input 元素,以及其他 HTML 元素(如 img)和鏈接(a 元素)。如果元素和文本是完全不同的類型,就必須為每種類型編寫完全不同的代碼。

如果使用一種通用節(jié)點類型情況就不同了。這時候只需要從一個節(jié)點移動到另一個節(jié)點,只有當需要對元素或文本作某種特殊處理時才需要考慮節(jié)點的類型。如果僅僅在 DOM 樹中移動,就可以與其他節(jié)點類型一樣用同樣的操作移動到元素的父節(jié)點或者子節(jié)點。只有當需要某種節(jié)點類型的特殊性質(zhì)時,如元素的屬性,才需要對節(jié)點類型作專門處理。將 DOM 樹中的所有對象都看作節(jié)點可以簡化操作。記住這一點之后,接下來我們將具體看看 DOM 節(jié)點構(gòu)造應(yīng)該提供什么,首先從屬性和方法開始。





回頁首


節(jié)點的屬性

使用 DOM 節(jié)點時需要一些屬性和方法,因此我們首先來討論節(jié)點的屬性和方法。DOM 節(jié)點的屬性主要有:

  • nodeName 報告節(jié)點的名稱(詳見下述)。
  • nodeValue 提供節(jié)點的 “值”(詳見后述)。
  • parentNode 返回節(jié)點的父節(jié)點。記住,每個元素、屬性和文本都有一個父節(jié)點。
  • childNodes 是節(jié)點的孩子節(jié)點列表。對于 HTML,該列表僅對元素有意義,文本節(jié)點和屬性節(jié)點都沒有孩子。
  • firstChild 僅僅是 childNodes 列表中第一個節(jié)點的快捷方式。
  • lastChild 是另一種快捷方式,表示 childNodes 列表中的最后一個節(jié)點。
  • previousSibling 返回當前節(jié)點之前 的節(jié)點。換句話說,它返回當前節(jié)點的父節(jié)點的 childNodes 列表中位于該節(jié)點前面的那個節(jié)點(如果感到迷惑,重新讀前面一句)。
  • nextSibling 類似于 previousSibling 屬性,返回父節(jié)點的 childNodes 列表中的下一個節(jié)點。
  • attributes 僅用于元素節(jié)點,返回元素的屬性列表。

其他少數(shù)幾種屬性實際上僅用于更一般的 XML 文檔,在處理基于 HTML 的網(wǎng)頁時沒有多少用處。

不常用的屬性

上述大部分屬性的意義都很明確,除了 nodeNamenodeValue 屬性以外。我們不是簡單地解釋這兩個屬性,而是提出兩個奇怪的問題:文本節(jié)點的 nodeName 應(yīng)該是什么?類似地,元素的 nodeValue 應(yīng)該是什么?

如果這些問題難住了您,那么您就已經(jīng)了解了這些屬性固有的含糊性。nodeNamenodeValue 實際上并非適用于所有 節(jié)點類型(節(jié)點的其他少數(shù)幾個屬性也是如此)。這就說明了一個重要概念:任何這些屬性都可能返回空值(有時候在 JavaScript 中稱為 “未定義”)。比方說,文本節(jié)點的 nodeName 屬性是空值(或者在一些瀏覽器中稱為 “未定義”),因為文本節(jié)點沒有名稱。如您所料,nodeValue 返回節(jié)點的文本。

類似地,元素有 nodeName,即元素名,但元素的 nodeValue 屬性值總是空。屬性同時具有 nodeNamenodeValue。下一節(jié)我還將討論這些單獨的類型,但是因為這些屬性是每個節(jié)點的一部分,因此在這里有必要提一提。

現(xiàn)在看看 清單 1,它用到了一些節(jié)點屬性。


清單 1. 使用 DOM 中的節(jié)點屬性
                            // These first two lines get the DOM tree for the current Web page,                        //   and then the <html> element for that DOM tree                        var myDocument = document;                        var htmlElement = myDocument.documentElement;                        // What‘s the name of the <html> element? "html"                        alert("The root element of the page is " + htmlElement.nodeName);                        // Look for the <head> element                        var headElement = htmlElement.getElementsByTagName("head")[0];                        if (headElement != null) {                        alert("We found the head element, named " + headElement.nodeName);                        // Print out the title of the page                        var titleElement = headElement.getElementsByTagName("title")[0];                        if (titleElement != null) {                        // The text will be the first child node of the <title> element                        var titleText = titleElement.firstChild;                        // We can get the text of the text node with nodeValue                        alert("The page title is ‘" + titleText.nodeValue + "‘");                        }                        // After <head> is <body>                        var bodyElement = headElement.nextSibling;                        while (bodyElement.nodeName.toLowerCase() != "body") {                        bodyElement = bodyElement.nextSibling;                        }                        // We found the <body> element...                        // We‘ll do more when we know some methods on the nodes.                        }                        





回頁首


節(jié)點方法

接下來看看所有節(jié)點都具有的方法(與節(jié)點屬性一樣,我省略了實際上不適用于多數(shù) HTML DOM 操作的少數(shù)方法):

  • insertBefore(newChild, referenceNode)newChild 節(jié)點插入到 referenceNode 之前。記住,應(yīng)該對 newChild 的目標父節(jié)點調(diào)用該方法。
  • replaceChild(newChild, oldChild)newChild 節(jié)點替換 oldChild 節(jié)點。
  • removeChild(oldChild) 從運行該方法的節(jié)點中刪除 oldChild 節(jié)點。
  • appendChild(newChild)newChild 添加到運行該函數(shù)的節(jié)點之中。newChild 被添加到目標節(jié)點孩子列表中的末端。
  • hasChildNodes() 在調(diào)用該方法的節(jié)點有孩子時則返回 true,否則返回 false。
  • hasAttributes() 在調(diào)用該方法的節(jié)點有屬性時則返回 true,否則返回 false。

注意,大部分情況下所有這些方法處理的都是節(jié)點的孩子。這是它們的主要用途。如果僅僅想獲取文本節(jié)點值或者元素名,則不需要調(diào)用這些方法,使用節(jié)點屬性就可以了。清單 2清單 1 的基礎(chǔ)上增加了方法使用。


清單 2. 使用 DOM 中的節(jié)點方法
                        // These first two lines get the DOM tree for the current Web page,                        //   and then the <html> element for that DOM tree                        var myDocument = document;                        var htmlElement = myDocument.documentElement;                        // What‘s the name of the <html> element? "html"                        alert("The root element of the page is " + htmlElement.nodeName);                        // Look for the <head> element                        var headElement = htmlElement.getElementsByTagName("head")[0];                        if (headElement != null) {                        alert("We found the head element, named " + headElement.nodeName);                        // Print out the title of the page                        var titleElement = headElement.getElementsByTagName("title")[0];                        if (titleElement != null) {                        // The text will be the first child node of the <title> element                        var titleText = titleElement.firstChild;                        // We can get the text of the text node with nodeValue                        alert("The page title is ‘" + titleText.nodeValue + "‘");                        }                        // After <head> is <body>                        var bodyElement = headElement.nextSibling;                        while (bodyElement.nodeName.toLowerCase() != "body") {                        bodyElement = bodyElement.nextSibling;                        }                        // We found the <body> element...                        // Remove all the top-level <img> elements in the body                        if (bodyElement.hasChildNodes()) {                        for (i=0; i<bodyElement.childNodes.length; i++) {                        var currentNode = bodyElement.childNodes[i];                        if (currentNode.nodeName.toLowerCase() == "img") {                        bodyElement.removeChild(currentNode);                        }                        }                        }                        }                        

測試一下!

目前雖然只看到了兩個例子,清單 12,不過通過這兩個例子您應(yīng)該能夠了解使用 DOM 樹能夠做什么。如果要嘗試一下這些代碼,只需要將 清單 3 拖入一個 HTML 文件并保存,然后用 Web 瀏覽器打開。


清單 3. 包含使用 DOM 的 JavaScript 代碼的 HTML 文件
                        <html>                        <head>                        <title>JavaScript and the DOM</title>                        <script language="JavaScript">                        function test() {                        // These first two lines get the DOM tree for the current Web page,                        //   and then the <html> element for that DOM tree                        var myDocument = document;                        var htmlElement = myDocument.documentElement;                        // What‘s the name of the <html> element? "html"                        alert("The root element of the page is " + htmlElement.nodeName);                        // Look for the <head> element                        var headElement = htmlElement.getElementsByTagName("head")[0];                        if (headElement != null) {                        alert("We found the head element, named " + headElement.nodeName);                        // Print out the title of the page                        var titleElement = headElement.getElementsByTagName("title")[0];                        if (titleElement != null) {                        // The text will be the first child node of the <title> element                        var titleText = titleElement.firstChild;                        // We can get the text of the text node with nodeValue                        alert("The page title is ‘" + titleText.nodeValue + "‘");                        }                        // After <head> is <body>                        var bodyElement = headElement.nextSibling;                        while (bodyElement.nodeName.toLowerCase() != "body") {                        bodyElement = bodyElement.nextSibling;                        }                        // We found the <body> element...                        // Remove all the top-level <img> elements in the body                        if (bodyElement.hasChildNodes()) {                        for (i=0; i<bodyElement.childNodes.length; i++) {                        var currentNode = bodyElement.childNodes[i];                        if (currentNode.nodeName.toLowerCase() == "img") {                        bodyElement.removeChild(currentNode);                        }                        }                        }                        }                        }                        </script>                        </head>                        <body>                        <p>JavaScript and DOM are a perfect match.                        You can read more in <i>Head Rush Ajax</i>.</p>                        <img src="http://www.headfirstlabs.com/Images/hraj_cover-150.jpg" />                        <input type="button" value="Test me!" onClick="test();" />                        </body>                        </html>                        

將該頁面加載到瀏覽器后,可以看到類似 圖 1 所示的畫面。


圖 1. 用按鈕運行 JavaScript 的 HTML 頁面

單擊 Test me! 將看到 圖 2 所示的警告框。


圖 2. 使用 nodeValue 顯示元素名的警告框

代碼運行完成后,圖片將從頁面中實時刪除,如 圖 3 所示。


圖 3. 使用 JavaScript 實時刪除圖像





回頁首


API 設(shè)計問題

再看一看各種節(jié)點提供的屬性和方法。對于那些熟悉面向?qū)ο螅∣O)編程的人來說,它們說明了 DOM 的一個重要特點:DOM 并非完全面向?qū)ο蟮?API。首先,很多情況下要直接使用對象的屬性而不是調(diào)用節(jié)點對象的方法。比方說,沒有 getNodeName() 方法,而要直接使用 nodeName 屬性。因此節(jié)點對象(以及其他 DOM 對象)通過屬性而不是函數(shù)公開了大量數(shù)據(jù)。

其次,如果習慣于使用重載對象和面向?qū)ο蟮?API,特別是 Java 和 C++ 這樣的語言,就會發(fā)現(xiàn) DOM 中的對象和方法命名有點奇怪。DOM 必須能用于 C、Java 和 JavaScript(這只是其中的幾種語言),因此 API 設(shè)計作了一些折衷。比如,NamedNodeMap 方法有兩種不同的形式:

  • getNamedItem(String name)
  • getNamedItemNS(Node node)

對于 OO 程序員來說這看起來非常奇怪。兩個方法目的相同,只不過一個使用 String 參數(shù)而另一個使用 Node 參數(shù)。多數(shù) OO API 中對這兩種版本都會使用相同的方法名。運行代碼的虛擬機將根據(jù)傳遞給方法的對象類型決定運行哪個方法。

問題在于 JavaScript 不支持這種稱為方法重載 的技術(shù)。換句話說,JavaScript 要求每個方法或函數(shù)使用不同的名稱。因此,如果有了一個名為 getNamedItem() 的接受字符串參數(shù)的方法,就不能再有另一個方法或函數(shù)也命名為 getNamedItem(),即使這個方法的參數(shù)類型不同(或者完全不同的一組參數(shù))。如果這樣做,JavaScript 將報告錯誤,代碼不會按照預期的方式執(zhí)行。

從根本上說,DOM 有意識地避開了方法重載和其他 OO 編程技術(shù)。這是為了保證該 API 能夠用于多種語言,包括那些不支持 OO 編程技術(shù)的語言。后果不過是要求您多記住一些方法名而已。好處是可以在任何語言中學習 DOM,比如 Java,并清楚同樣的方法名和編碼結(jié)構(gòu)也能用于具有 DOM 實現(xiàn)的其他語言,如 JavaScript。

讓程序員小心謹慎

如果深入研究 API 設(shè)計或者僅僅非常關(guān)注 API 設(shè)計,您可能會問:“為何節(jié)點類型的屬性不能適用于所有節(jié)點?” 這是一個很好的問題,問題的答案與政治及決策關(guān)系更密切,而非技術(shù)原因。簡單地說,答案就是,“誰知道!但有點令人惱火,不是嗎?”

屬性 nodeName 意味著允許每種類型的節(jié)點都有一個名字,但是很多情況下名字要么未定義,要么是對于程序員沒有意義的內(nèi)部名(比如在 Java 中,很多情況下文本節(jié)點的 nodeName 被報告為 “#text”)。從根本上說,必須假設(shè)您得自己來處理錯誤。直接訪問 myNode.nodeName 然后使用該值是危險的,很多情況下這個值為空。因此與通常的編程一樣,程序員要謹慎從事。





回頁首


通用節(jié)點類型

現(xiàn)在已經(jīng)介紹了 DOM 節(jié)點的一些特性和屬性(以及一些奇特的地方),下面開始講述您將用到的一些特殊節(jié)點類型。多數(shù) Web 應(yīng)用程序中只用到四種節(jié)點類型:

  • 文檔節(jié)點表示整個 HTML 文檔。
  • 元素節(jié)點表示 HTML 元素,如 aimg。
  • 屬性節(jié)點表示 HTML 元素的屬性,如 hrefa 元素)或 srcimg 元素)。
  • 文本節(jié)點表示 HTML 文檔中的文本,如 “Click on the link below for a complete set list”。這是出現(xiàn)在 pah2 這些元素中的文字。

處理 HTML 時,95% 的時間是跟這些節(jié)點類型打交道。因此本文的其余部分將詳細討論這些節(jié)點。(將來討論 XML 的時候?qū)⒔榻B其他一些節(jié)點類型。)





回頁首


文檔節(jié)點

基本上所有基于 DOM 的代碼中都要用到的第一個節(jié)點類型是文檔節(jié)點。文檔節(jié)點 實際上并不是 HTML(或 XML)頁面中的一個元素而是頁面本身。因此在 HTML Web 頁面中,文檔節(jié)點就是整個 DOM 樹。在 JavaScript 中,可以使用關(guān)鍵字 document 訪問文檔節(jié)點:

                        // These first two lines get the DOM tree for the current Web page,                        //   and then the <html> element for that DOM tree                        var myDocument = document;                        var htmlElement = myDocument.documentElement;                        

JavaScript 中的 document 關(guān)鍵字返回當前網(wǎng)頁的 DOM 樹。從這里可以開始處理樹中的所有節(jié)點。

也可使用 document 對象創(chuàng)建新節(jié)點,如下所示:

  • createElement(elementName) 使用給定的名稱創(chuàng)建一個元素。
  • createTextNode(text) 使用提供的文本創(chuàng)建一個新的文本節(jié)點。
  • createAttribute(attributeName) 用提供的名稱創(chuàng)建一個新屬性。

這里的關(guān)鍵在于這些方法創(chuàng)建節(jié)點,但是并沒有將其附加或者插入到特定的文檔中。因此,必須使用前面所述的方法如 insertBefore()appendChild() 來完成這一步。因此,可使用下面的代碼創(chuàng)建新元素并將其添加到文檔中:

                        var pElement = myDocument.createElement("p");                        var text = myDocument.createTextNode("Here‘s some text in a p element.");                        pElement.appendChild(text);                        bodyElement.appendChild(pElement);                        

一旦使用 document 元素獲得對 Web 頁面 DOM 樹的訪問,就可以直接使用元素、屬性和文本了。





回頁首


元素節(jié)點

雖然會大量使用元素節(jié)點,但很多需要對元素執(zhí)行的操作都是所有節(jié)點共有的方法和屬性,而不是元素特有的方法和屬性。元素只有兩組專有的方法:

  1. 與屬性處理有關(guān)的方法
    • getAttribute(name) 返回名為 name 的屬性值。
    • removeAttribute(name) 刪除名為 name 的屬性。
    • setAttribute(name, value) 創(chuàng)建一個名為 name 的屬性并將其值設(shè)為 value。
    • getAttributeNode(name) 返回名為 name 的屬性節(jié)點(屬性節(jié)點在 下一節(jié) 介紹)。
    • removeAttributeNode(node) 刪除與指定節(jié)點匹配的屬性節(jié)點。
  2. 與查找嵌套元素有關(guān)的方法
    • getElementsByTagName(elementName) 返回具有指定名稱的元素節(jié)點列表。

這些方法意義都很清楚,但還是來看幾個例子吧。

處理屬性

處理元素很簡單,比如可用 document 對象和上述方法創(chuàng)建一個新的 img 元素:

                        var imgElement = document.createElement("img");                        imgElement.setAttribute("src", "http://www.headfirstlabs.com/Images/hraj_cover-150.jpg");                        imgElement.setAttribute("width", "130");                        imgElement.setAttribute("height", "150");                        bodyElement.appendChild(imgElement);                        

現(xiàn)在看起來應(yīng)該非常簡單了。實際上,只要理解了節(jié)點的概念并知道有哪些方法可用,就會發(fā)現(xiàn)在 Web 頁面和 JavaScript 代碼中處理 DOM 非常簡單。在上述代碼中,JavaScript 創(chuàng)建了一個新的 img 元素,設(shè)置了一些屬性然后添加到 HTML 頁面的 body 元素中。

查找嵌套元素

發(fā)現(xiàn)嵌套的元素很容易。比如,下面的代碼用于發(fā)現(xiàn)和刪除 清單 3 所示 HTML 頁面中的所有 img 元素:

                              // Remove all the top-level <img> elements in the body                        if (bodyElement.hasChildNodes()) {                        for (i=0; i<bodyElement.childNodes.length; i++) {                        var currentNode = bodyElement.childNodes[i];                        if (currentNode.nodeName.toLowerCase() == "img") {                        bodyElement.removeChild(currentNode);                        }                        }                        }                        

也可以使用 getElementsByTagName() 完成類似的功能:

                                                // Remove all the top-level <img> elements in the body                        var imgElements = bodyElement.getElementsByTagName("img");                        for (i=0; i<imgElements.length; i++) {                        var imgElement = imgElements.item[i];                        bodyElement.removeChild(imgElement);                        }                        





回頁首


屬性節(jié)點

DOM 將屬性表示成節(jié)點,可以通過元素的 attributes 來訪問元素的屬性,如下所示:

                                                // Remove all the top-level <img> elements in the body                        var imgElements = bodyElement.getElementsByTagName("img");                        for (i=0; i<imgElements.length; i++) {                        var imgElement = imgElements.item[i];                        // Print out some information about this element                        var msg = "Found an img element!";                        var atts = imgElement.attributes;                        for (j=0; j<atts.length; j++) {                        var att = atts.item(j);                        msg = msg + "\n  " + att.nodeName + ": ‘" + att.nodeValue + "‘";                        }                        alert(msg);                        bodyElement.removeChild(imgElement);                        }                        

屬性的奇特之處

對于 DOM 來說屬性有一些特殊的地方。一方面,屬性實際上并不像其他元素或文本那樣是元素的孩子,換句話說,屬性并不出現(xiàn)在元素 “之下”。同時,屬性顯然和元素有一定的關(guān)系,元素 “擁有” 屬性。DOM 使用節(jié)點表示屬性,并允許通過元素的專門列表來訪問屬性。因此屬性是 DOM 樹的一部分,但通常不出現(xiàn)在樹中。有理由說,屬性和 DOM 樹結(jié)構(gòu)其他部分之間的關(guān)系有點模糊。

需要指出的是,attributes 屬性實際上是對節(jié)點類型而非局限于元素類型來說的。有點古怪,不影響您編寫代碼,但是仍然有必要知道這一點。

雖然也能使用屬性節(jié)點,但通常使用元素類的方法處理屬性更簡單。其中包括:

  • getAttribute(name) 返回名為 name 的屬性值。
  • removeAttribute(name) 刪除名為 name 的屬性。
  • setAttribute(name, value) 創(chuàng)建一個名為 name 的屬性并將其值設(shè)為 value。

這三個方法不需要直接處理屬性節(jié)點。但允許使用簡單的字符串屬性設(shè)置和刪除屬性及其值。





回頁首


文本節(jié)點

需要考慮的最后一種節(jié)點是文本節(jié)點(至少在處理 HTML DOM 樹的時候如此)?;旧贤ǔS糜谔幚砦谋竟?jié)點的所有屬性都屬于節(jié)點對象。實際上,一般使用 nodeValue 屬性來訪問文本節(jié)點的文本,如下所示:

                        var pElements = bodyElement.getElementsByTagName("p");                        for (i=0; i<pElements.length; i++) {                        var pElement = pElements.item(i);                        var text = pElement.firstChild.nodeValue;                        alert(text);                        }                        

少數(shù)其他幾種方法是專門用于文本節(jié)點的。這些方法用于增加或分解節(jié)點中的數(shù)據(jù):

  • appendData(text) 將提供的文本追加到文本節(jié)點的已有內(nèi)容之后。
  • insertData(position, text) 允許在文本節(jié)點的中間插入數(shù)據(jù)。在指定的位置插入提供的文本。
  • replaceData(position, length, text) 從指定位置開始刪除指定長度的字符,用提供的文本代替刪除的文本。




回頁首


什么節(jié)點類型?

到目前為止看到的多數(shù)代碼都假設(shè)已經(jīng)知道處理的節(jié)點是什么類型,但情況并非總是如此。比方說,如果在 DOM 樹中導航并處理一般的節(jié)點類型,可能就不知道您遇到了元素還是文本。也許獲得了 p 元素的所有孩子,但是不能確定處理的是文本、b 元素還是 img 元素。這種情況下,在進一步的處理之前需要確定是什么類型的節(jié)點。

所幸的是很容易就能做到。DOM 節(jié)點類型定義了一些常量,比如:

  1. Node.ELEMENT_NODE 是表示元素節(jié)點類型的常量。
  2. Node.ATTRIBUTE_NODE 是表示屬性節(jié)點類型的常量。
  3. Node.TEXT_NODE 是表示文本節(jié)點類型的常量。
  4. Node.DOCUMENT_NODE 是表示文檔節(jié)點類型的常量。

還有其他一些節(jié)點類型,但是對于 HTML 除了這四種以外很少用到。我有意沒有給出這些常量的值,雖然 DOM 規(guī)范中定義了這些值,永遠不要直接使用那些值,因為這正是常量的目的!

nodeType 屬性

可使用 nodeType 屬性比較節(jié)點和上述常量 —— 該屬性定義在 DOM node 類型上因此可用于所有節(jié)點,如下所示:

                        var someNode = document.documentElement.firstChild;                        if (someNode.nodeType == Node.ELEMENT_NODE) {                        alert("We‘ve found an element node named " + someNode.nodeName);                        } else if (someNode.nodeType == Node.TEXT_NODE) {                        alert("It‘s a text node; the text is " + someNode.nodeValue);                        } else if (someNode.nodeType == Node.ATTRIBUTE_NODE) {                        alert("It‘s an attribute named " + someNode.nodeName                        + " with a value of ‘" + someNode.nodeValue + "‘");                        }                        

這個例子非常簡單,但說明了一個大問題:得到節(jié)點的類型非常 簡單。更有挑戰(zhàn)性的是知道節(jié)點的類型之后確定能做什么,只要掌握了節(jié)點、文本、屬性和元素類型提供了什么屬性和方法,就可以自己進行 DOM 編程了。

好了,快結(jié)束了。

實踐中的挫折

nodeType 屬性似乎是使用節(jié)點的一個入場券 —— 允許確定要處理的節(jié)點類型然后編寫處理該節(jié)點的代碼。問題在于上述 Node 常量定義不能正確地用于 Internet Explorer。因此如果在代碼中使用 Node.ELEMENT_NODE、Node.TEXT_NODE 或其他任何常量,Internet Explorer 都將返回如 圖 4 所示的錯誤。


圖 4. Internet Explorer 報告錯誤

任何時候在 JavaScript 中使用 Node 常量,Internet Explorer 都會報錯。因為多數(shù)人仍然在使用 Internet Explorer,應(yīng)該避免在代碼中使用 Node.ELEMENT_NODENode.TEXT_NODE 這樣的構(gòu)造。盡管據(jù)說即將發(fā)布的新版本 Internet Explorer 7.0 將解決這個問題,但是在 Internet Explorer 6.x 退出舞臺之前仍然要很多年。因此應(yīng)避免使用 Node,要想讓您的 DOM 代碼(和 Ajax 應(yīng)用程序)能用于所有主要瀏覽器,這一點很重要。





回頁首


結(jié)束語

準備成為頂尖的網(wǎng)頁設(shè)計師嗎?

如果您準備了解甚至掌握 DOM,您就會成為最頂尖的 Web 編程人員。多數(shù) Web 程序員知道如何使用 JavaScript 編寫圖像滾動或者從表單中提取值,有些甚至能夠向服務(wù)器發(fā)送請求和接收響應(yīng)(閱讀本系列的前幾篇文章之后您也能做到)。但膽小鬼或者沒有經(jīng)驗的人不可能做到即時修改網(wǎng)頁結(jié)構(gòu)。

在本系列的上幾期文章中您已經(jīng)學習了很多?,F(xiàn)在,您 應(yīng)該再坐等下一篇文章期待我介紹各種聰明的 DOM 樹用法?,F(xiàn)在的家庭作業(yè)是看看如何使用 DOM 創(chuàng)造出富有想像力的效果或者漂亮的界面。利用近幾期文章中所學的知識開始實驗和練習??纯茨芊窠⒏杏X更與桌面應(yīng)用程序接近的網(wǎng)站,對象能夠響應(yīng)用戶的動作在屏幕上移動。

最好在屏幕上為每個對象畫一個邊界,這樣就能看到 DOM 樹中的對象在何處,然后再移動對象。創(chuàng)建節(jié)點并將其添加到已有的孩子列表中,刪除沒有嵌套節(jié)點的空節(jié)點,改變節(jié)點的 CSS 樣式,看看孩子節(jié)點是否會繼承這些修改。可能性是無限的,每當嘗試一些新東西時,就學到了一些新的知識。盡情地修改您的網(wǎng)頁吧!

在 DOM 三部曲的最后一期文章中,我 介紹如何把一些非常棒的有趣的 DOM 應(yīng)用結(jié)合到編程中。我將不再是從概念上說教和解釋 API,而會提供一些代碼。在此之前先發(fā)揮您自己的聰明才智,看看能做些什么。





回頁首


參考資料

學習

獲得產(chǎn)品和技術(shù)
  • Brett McLaughlin 所著的 Head Rush Ajax(O‘Reilly Media, Inc.,2006 年 3 月):深入淺出地將本文中的思想印入您的腦海。

  • Java and XML, Second Edition(Brett McLaughlin,2001 年 8 月,O‘Reilly Media, Inc.):看看作者關(guān)于 XHTML 和 XML 轉(zhuǎn)換的討論。

  • JavaScript: The Definitive Guide(David Flanagan,2001 年 11 月,O‘Reilly Media, Inc.):深入了解關(guān)于使用 JavaScript 和動態(tài) Web 頁面的各種建議。下一版將增加關(guān)于 Ajax 的兩章。

  • Head First HTML with CSS & XHTML(Elizabeth 與 Eric Freeman,2005 年 12 月,O‘Reilly Media, Inc.):進一步了解標準 HTML 和 XHTML,以及如何將 CSS 應(yīng)用于 HTML。

  • IBM 試用軟件:用這些軟件開發(fā)您的下一個項目,可直接從 developerWorks 下載。

討論




回頁首


關(guān)于作者

Brett McLaughlin 從 Log 時代就開始使用計算機了。(還記得那個小三角嗎?)近年來,他已經(jīng)成為 Java 和 XML 社區(qū)中最受歡迎的作者和程序員之一了。他曾經(jīng)在 Nextel Communications 實現(xiàn)過復雜的企業(yè)系統(tǒng),在 Lutris Technologies 編寫過應(yīng)用服務(wù)器,最近在 O‘Reilly Media, Inc. 繼續(xù)撰寫和編輯這方面的圖書。Brett 最新的著作 Head Rush Ajax,為 Ajax 帶來了獲獎的創(chuàng)新 Head First 方法。他的近作 Java 1.5 Tiger: A Developer‘s Notebook 是關(guān)于這一 Java 技術(shù)最新版本的第一部專著。經(jīng)典作品 Java and XML 仍然是在 Java 語言中使用 XML 技術(shù)的權(quán)威著作之一。






回頁首

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
第 5 部分 操縱 DOM使用 JavaScript 即時更新 Web 頁面 (2)
Web API——DOM介紹
XML DOM介紹
javascript中的NodeType、NodeValue、NodeName實例測試
DOM節(jié)點信息、DOM屬性、3大節(jié)點、替換節(jié)點、查找設(shè)置屬性節(jié)點、創(chuàng)建刪除插入節(jié)點、innerHTML屬性、顯示彈出窗口
JavaScript獲取節(jié)點類型、節(jié)點名稱和節(jié)點值
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服