国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript 編程精解 中文第三版 十四、文檔對象模型

gggggggbong / 2221人閱讀

摘要:在其沙箱中提供了將文本轉換成文檔對象模型的功能。瀏覽器使用與該形狀對應的數據結構來表示文檔。我們將這種表示方式稱為文檔對象模型,或簡稱。樹回想一下第章中提到的語法樹。語言的語法樹有標識符值和應用節點。元素表示標簽的節點用于確定文檔結構。

來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目

原文:The Document Object Model

譯者:飛龍

協議:CC BY-NC-SA 4.0

自豪地采用谷歌翻譯

部分參考了《JavaScript 編程精解(第 2 版)》

Too bad! Same old story! Once you"ve finished building your house you notice you"ve accidentally learned something that you really should have known—before you started.

Friedrich Nietzsche,《Beyond Good and Evil》

當你在瀏覽器中打開網頁時,瀏覽器會接收網頁的 HTML 文本并進行解析,其解析方式與第 11 章中介紹的解析器非常相似。瀏覽器構建文檔結構的模型,并使用該模型在屏幕上繪制頁面。

JavaScript 在其沙箱中提供了將文本轉換成文檔對象模型的功能。它是你可以讀取或者修改的數據結構。模型是一個所見即所得的數據結構,改變模型會使得屏幕上的頁面產生相應變化。

文檔結構

你可以將 HTML 文件想象成一系列嵌套的箱子。諸如之類的標簽會將其他標簽包圍起來,而包含在內部的標簽也可以包含其他的標簽和文本。這里給出上一章中已經介紹過的示例文件。



  
    My home page
  
  
    

My home page

Hello, I am Marijn and this is my home page.

I also wrote a book! Read it here.

該頁面結構如下所示。

瀏覽器使用與該形狀對應的數據結構來表示文檔。每個盒子都是一個對象,我們可以和這些對象交互,找出其中包含的盒子與文本。我們將這種表示方式稱為文檔對象模型(Document Object Model),或簡稱 DOM。

我們可以通過全局綁定document來訪問這些對象。該對象的documentElement屬性引用了標簽對象。由于每個 HTML 文檔都有一個頭部和一個主體,它還具有headbody屬性,指向這些元素。

回想一下第 12 章中提到的語法樹。其結構與瀏覽器文檔的結構極為相似。每個節點使用children引用其他節點,而每個子節點又有各自的children。其形狀是一種典型的嵌套結構,每個元素可以包含與其自身相似的子元素。

如果一個數據結構有分支結構,而且沒有任何環路(一個節點不能直接或間接包含自身),并且有一個單一、定義明確的“根節點”,那么我們將這種數據結構稱之為樹。就 DOM 來講,document.documentElement就是其根節點。

在計算機科學中,樹的應用極為廣泛。除了表現諸如 HTML 文檔或程序之類的遞歸結構,樹還可以用于維持數據的有序集合,因為在樹中尋找或插入一個節點往往比在數組中更高效。

一棵典型的樹有不同類型的節點。Egg 語言的語法樹有標識符、值和應用節點。應用節點常常包含子節點,而標識符、值則是葉子節點,也就是沒有子節點的節點。

DOM中也是一樣。元素(表示 HTML 標簽)的節點用于確定文檔結構。這些節點可以包含子節點。這類節點中的一個例子是document.body。其中一些子節點可以是葉子節點,比如文本片段或注釋。

每個 DOM 節點對象都包含nodeType屬性,該屬性包含一個標識節點類型的代碼(數字)。元素的值為 1,DOM 也將該值定義成一個常量屬性document.ELEMENT_NODE。文本節點(表示文檔中的一段文本)代碼為 3(document.TEXT_NODE)。注釋的代碼為 8(document.COMMENT_NODE)。

因此我們可以使用另一種方法來表示文檔樹:

葉子節點是文本節點,而箭頭則指出了節點之間的父子關系。

標準

并非只有 JavaScript 會使用數字代碼來表示節點類型。本章隨后將會展示其他的 DOM 接口,你可能會覺得這些接口有些奇怪。這是因為 DOM 并不是為 JavaScript 而設計的,它嘗試成為一組語言中立的接口,確保也可用于其他系統中,不只是 HTML,還有 XML。XML 是一種通用數據格式,語法與 HTML 相近。

這就比較糟糕了。一般情況下標準都是非常易于使用的。但在這里其優勢(跨語言的一致性)并不明顯。相較于為不同語言提供類似的接口,如果能夠將接口與開發者使用的語言進行適當集成,可以為開發者節省大量時間。

我們舉例來說明一下集成問題。比如 DOM 中每個元素都有childNodes屬性。該屬性是一個類數組對象,有length屬性,也可以使用數字標簽訪問對應的子節點。但該屬性是NodeList類型的實例,而不是真正的數組,因此該類型沒有諸如slicemap之類的方法。

有些問題是由不好的設計導致的。例如,我們無法在創建新的節點的同時立即為其添加子節點和屬性。相反,你首先需要創建節點,然后使用副作用,將子節點和屬性逐個添加到節點中。大量使用 DOM 的代碼通常較長、重復和丑陋。

但這些問題并非無法改善。因為 JavaScript 允許我們構建自己的抽象,可以設計改進方式來表達你正在執行的操作。 許多用于瀏覽器編程的庫都附帶這些工具。

沿著樹移動

DOM 節點包含了許多指向相鄰節點的鏈接。下面的圖表展示了這一點。

盡管圖表中每種類型的節點只顯示出一條鏈接,但每個節點都有parentNode屬性,指向一個節點,它是這個節點的一部分。類似的,每個元素節點(節點類型為 1)均包含childNodes屬性,該屬性指向一個類數組對象,用于保存其子節點。

理論上,你可以通過父子之間的鏈接移動到樹中的任何地方。但 JavaScript 也提供了一些更加方便的額外鏈接。firstChild屬性和lastChild屬性分別指向第一個子節點和最后一個子節點,若沒有子節點則值為null。類似的,previousSiblingnextSibling指向相鄰節點,分別指向擁有相同父親的前一個節點和后一個節點。對于第一個子節點,previousSiblingnull,而最后一個子節點的nextSibling則是null

也存在children屬性,它就像childNodes,但只包含元素(類型為 1)子節點,而不包含其他類型的子節點。 當你對文本節點不感興趣時,這可能很有用。

處理像這樣的嵌套數據結構時,遞歸函數通常很有用。 以下函數在文檔中掃描包含給定字符串的文本節點,并在找到一個時返回true

function talksAbout(node, string) {
  if (node.nodeType == document.ELEMENT_NODE) {
    for (let i = 0; i < node.childNodes.length; i++) {
      if (talksAbout(node.childNodes[i], string)) {
        return true;
      }
    }
    return false;
  } else if (node.nodeType == document.TEXT_NODE) {
    return node.nodeValue.indexOf(string) > -1;
  }
}

console.log(talksAbout(document.body, "book"));
// → true

因為childNodes不是真正的數組,所以我們不能用for/of來遍歷它,并且必須使用普通的for循環遍歷索引范圍。

文本節點的nodeValue屬性保存它所表示的文本字符串。

查找元素

使用父節點、子節點和兄弟節點之間的連接遍歷節點確實非常實用。但是如果我們只想查找文檔中的特定節點,那么從document.body開始盲目沿著硬編碼的鏈接路徑查找節點并非良策。如果程序通過樹結構定位節點,就需要依賴于文檔的具體結構,而文檔結構隨后可能發生變化。另一個復雜的因素是 DOM 會為不同節點之間的空白字符創建對應的文本節點。例如示例文檔中的body標簽不止包含 3 個子節點(

和兩個

元素),其實包含 7 個子節點:這三個節點、三個節點前后的空格、以及元素之間的空格。

因此,如果你想獲取文檔中某個鏈接的href屬性,最好不要去獲取文檔body元素中第六個子節點的第二個子節點,而最好直接獲取文檔中的第一個鏈接,而且這樣的操作確實可以實現。

let link = document.body.getElementsByTagName("a")[0];
console.log(link.href);

所有元素節點都包含getElementsByTagName方法,用于從所有后代節點中(直接或間接子節點)搜索包含給定標簽名的節點,并返回一個類數組的對象。

你也可以使用document.getElementById來尋找包含特定id屬性的某個節點。

My ostrich Gertrude:

第三個類似的方法是getElementsByClassName,它與getElementsByTagName類似,會搜索元素節點的內容并獲取所有包含特定class屬性的元素。

修改文檔

幾乎所有 DOM 數據結構中的元素都可以被修改。文檔樹的形狀可以通過改變父子關系來修改。 節點的remove方法將它們從當前父節點中移除。appendChild方法可以添加子節點,并將其放置在子節點列表末尾,而insertBefore則將第一個參數表示的節點插入到第二個參數表示的節點前面。

One

Two

Three

每個節點只能存在于文檔中的某一個位置。因此,如果將段落Three插入到段落One前,會將該節點從文檔末尾移除并插入到文檔前面,最后結果為Three/One/Two。所有將節點插入到某處的方法都有這種副作用——會將其從當前位置移除(如果存在的話)。

replaceChild方法用于將一個子節點替換為另一個子節點。該方法接受兩個參數,第一個參數是新節點,第二個參數是待替換的節點。待替換的節點必須是該方法調用者的子節點。這里需要注意,replaceChildinsertBefore都將新節點作為第一個參數。

創建節點

假設我們要編寫一個腳本,將文檔中的所有圖像(標簽)替換為其alt屬性中的文本,該文本指定了圖像的文字替代表示。

這不僅涉及刪除圖像,還涉及添加新的文本節點,并替換原有圖像節點。為此我們使用document.createTextNode方法。

The Cat in the Hat.

給定一個字符串,createTextNode為我們提供了一個文本節點,我們可以將它插入到文檔中,來使其顯示在屏幕上。

該循環從列表末尾開始遍歷圖像。我們必須這樣反向遍歷列表,因為getElementsByTagName之類的方法返回的節點列表是動態變化的。該列表會隨著文檔改變還改變。若我們從列表頭開始遍歷,移除掉第一個圖像會導致列表丟失其第一個元素,第二次循環時,因為集合的長度此時為 1,而i也為 1,所以循環會停止。

如果你想要獲得一個固定的節點集合,可以使用數組的Array.from方法將其轉換成實際數組。

let arrayish = {0: "one", 1: "two", length: 2};
let array = Array.from(arrayish);
console.log(array.map(s => s.toUpperCase()));
// → ["ONE", "TWO"]

你可以使用document.createElement方法創建一個元素節點。該方法接受一個標簽名,返回一個新的空節點,節點類型由標簽名指定。

下面的示例定義了一個elt工具,用于創建一個新的元素節點,并將其剩余參數當作該節點的子節點。接著使用該函數為引用添加來源信息。

No book can ever be finished. While working on it we learn just enough to find it immature the moment we turn away from it.
屬性

我們可以通過元素的 DOM 對象的同名屬性去訪問元素的某些屬性,比如鏈接的href屬性。這僅限于最常用的標準屬性。

HTML 允許你在節點上設定任何屬性。這一特性非常有用,因為這樣你就可以在文檔中存儲額外信息。你自己創建的屬性不會出現在元素節點的屬性中。你必須使用getAttributesetAttribute方法來訪問這些屬性。

The launch code is 00000000.

I have two feet.

建議為這些組合屬性的名稱添加data-前綴,來確保它們不與任何其他屬性發生沖突。

這里有一個常用的屬性:class。該屬性是 JavaScript 中的保留字。因為某些歷史原因(某些舊版本的 JavaScript 實現無法處理和關鍵字或保留字同名的屬性),訪問class的屬性名為className。你也可以使用getAttributesetAttribute方法,使用其實際名稱class來訪問該屬性。

布局

你可能已經注意到不同類型的元素有不同的布局。某些元素,比如段落(

)和標題(

)會占據整個文檔的寬度,并且在獨立的一行中渲染。這些元素被稱為塊(Block)元素。其他的元素,比如鏈接(元素則與周圍文本在同一行中渲染。這類元素我們稱之為內聯(Inline)元素。

對于任意特定文檔,瀏覽器可以根據每個元素的類型和內容計算其尺寸與位置等布局信息。接著使用布局來繪制文檔。

JavaScript 中可以訪問元素的尺寸與位置。

屬性offsetWidthoffsetHeight給出元素的起始位置(單位是像素)。像素是瀏覽器中的基本測量單元。它通常對應于屏幕可以繪制的最小的點,但是在現代顯示器上,可以繪制非常小的點,這可能不再適用了,并且瀏覽器像素可能跨越多個顯示點。

同樣,clientWidthclientHeight向你提供元素內的空間大小,忽略邊框寬度。

I"m boxed in

getBoundingClientRect方法是獲取屏幕中某個元素精確位置的最有效方法。該方法返回一個對象,包含topbottomleftright四個屬性,表示元素相對于屏幕左上角的位置(單位是像素)。若你想要知道其相對于整個文檔的位置,必須加上其滾動位置,你可以在pageXOffsetpageYOffset綁定中找到。

我們還需要花些力氣才能完成文檔的排版工作。為了加快速度,每次你改變它時,瀏覽器引擎不會立即重新繪制整個文檔,而是盡可能等待并推遲重繪操作。當一個修改文檔的 JavaScript 程序結束時,瀏覽器會計算新的布局,并在屏幕上顯示修改過的文檔。若程序通過讀取offsetHeightgetBoundingClientRect這類屬性獲取某些元素的位置或尺寸時,為了提供正確的信息,瀏覽器也需要計算布局。

如果程序反復讀取 DOM 布局信息或修改 DOM,會強制引發大量布局計算,導致運行非常緩慢。下面的代碼展示了一個示例。該示例包含兩個不同的程序,使用X字符構建一條線,其長度是 2000 像素,并計算每個任務的時間。

樣式

我們看到了不同的 HTML 元素的繪制是不同的。一些元素顯示為塊,一些則是以內聯方式顯示。我們還可以添加一些樣式,比如使用加粗內容,或使用使內容變成藍色,并添加下劃線。

標簽顯示圖片的方式或點擊標簽時跳轉的鏈接都和元素類型緊密相關。但元素的默認樣式,比如文本的顏色、是否有下劃線,都是可以改變的。這里給出使用style屬性的示例。

Normal link

Green link

樣式屬性可以包含一個或多個聲明,格式為屬性(比如color)后跟著一個冒號和一個值(比如green)。當包含更多聲明時,不同屬性之間必須使用分號分隔,比如color:red;border:none

文檔的很多方面會受到樣式的影響。例如,display屬性控制一個元素是否顯示為塊元素或內聯元素。

This text is displayed inline,
as a block, and
not at all.

block標簽會結束其所在的那一行,因為塊元素是不會和周圍文本內聯顯示的。最后一個標簽完全不會顯示出來,因為display:none會阻止一個元素呈現在屏幕上。這是隱藏元素的一種方式。更好的方式是將其從文檔中完全移除,因為稍后將其放回去是一件很簡單的事情。

JavaScript 代碼可以通過元素的style屬性操作元素的樣式。該屬性保存了一個對象,對象中存儲了所有可能的樣式屬性,這些屬性的值是字符串,我們可以把字符串寫入屬性,修改某些方面的元素樣式。

Nice text

一些樣式屬性名包含破折號,比如font-family。由于這些屬性的命名不適合在 JavaScript 中使用(你必須寫成style["font-family"]),因此在 JavaScript 中,樣式對象中的屬性名都移除了破折號,并將破折號之后的字母大寫(style.fontFamily)。

層疊樣式

我們把 HTML 的樣式化系統稱為 CSS,即層疊樣式表(Cascading Style Sheets)。樣式表是一系列規則,指出如何為文檔中元素添加樣式。可以在

Now strong text is italic and gray.

所謂層疊指的是將多條規則組合起來產生元素的最終樣式。在示例中,標簽的默認樣式font-weight:bold,會被

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/105049.html

相關文章

  • JavaScript 編程精解 中文三版 十三、瀏覽器中的 JavaScript

    摘要:在本例中,使用屬性指定鏈接的目標,其中表示超文本鏈接。您應該認為和元數據隱式出現在示例中,即使它們沒有實際顯示在文本中。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:JavaScript and the Browser 譯者:飛龍 協議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分參考了《JavaScript 編程精解(第 2 版)》 ...

    zhiwei 評論0 收藏0
  • JavaScript 編程精解 中文三版 十五、處理事件

    摘要:事件與節點每個瀏覽器事件處理器被注冊在上下文中。事件對象雖然目前為止我們忽略了它,事件處理器函數作為對象傳遞事件對象。若事件處理器不希望執行默認行為通常是因為已經處理了該事件,會調用事件對象的方法。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:Handling Events 譯者:飛龍 協議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 部分...

    Clect 評論0 收藏0
  • JavaScript 編程精解 中文三版 零、前言

    摘要:來源編程精解中文第三版翻譯項目原文譯者飛龍協議自豪地采用谷歌翻譯部分參考了編程精解第版,這是一本關于指導電腦的書。在可控的范圍內編寫程序是編程過程中首要解決的問題。我們可以用中文來描述這些指令將數字存儲在內存地址中的位置。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:Introduction 譯者:飛龍 協議:CC BY-NC-SA 4.0 自豪地...

    sanyang 評論0 收藏0
  • JavaScript 編程精解 中文三版 七、項目:機器人

    摘要:來源編程精解中文第三版翻譯項目原文譯者飛龍協議自豪地采用谷歌翻譯置疑計算機能不能思考就相當于置疑潛艇能不能游泳。這張圖將成為我們的機器人在其中移動的世界。機器人在收到包裹時拾取包裹,并在抵達目的地時將其送達。這個機器人已經快了很多。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:Project: A Robot 譯者:飛龍 協議:CC BY-NC-S...

    jas0n 評論0 收藏0
  • JavaScript 編程精解 中文三版 十、模塊

    摘要:來源編程精解中文第三版翻譯項目原文譯者飛龍協議自豪地采用谷歌翻譯編寫易于刪除,而不是易于擴展的代碼。模塊之間的關系稱為依賴關系。用于連接模塊的最廣泛的方法稱為模塊。模塊的主要概念是稱為的函數。 來源:ApacheCN『JavaScript 編程精解 中文第三版』翻譯項目原文:Modules 譯者:飛龍 協議:CC BY-NC-SA 4.0 自豪地采用谷歌翻譯 編寫易于刪除,而不是易于擴...

    justjavac 評論0 收藏0

發表評論

0條評論

gggggggbong

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<