JS之DOM

一、節點層次

DOM是針對 HTMLXML 文檔的一個API(應用程序編程接口)。DOM描繪了一個層次化的節點樹,允許開發人員添加、移除和修改頁面的某一部分。

DOM文檔對象模型

DOM 可以將任何 HTMLXML 文檔描繪成一個由多層節點構成的結構。節點分為幾種不同的類型,每種類型分別表示文檔中不同的信息及(或)標記。每個節點都擁有各自的特點、數據和方法,另外也與其他節點存在某種關系。節點之間的關系構成了層次,而所有頁面標記則表現為一個以特定節點為根節點的樹形結構。

文檔元素是文檔的最外層元素,文檔中的其他所有元素都包含在文檔元素中。每個文檔只能有一個文檔元素。在 HTML 頁面中,文檔元素始終都是 <html> 元素。在 XML 中,沒有預定義的元素,因此任何元素都可能成為文檔元素。

每一段標記都可以通過樹中的一個節點來表示:HTML 元素通過元素節點表示,特性(attribute)通過特性節點表示,文檔類型通過文檔類型節點表示,而注釋則通過注釋節點表示。總共有 12 種節點類型,這些類型都繼承自一個基類型。

1、Node類型

DOM1 級定義了一個 Node 接口,該接口將由 DOM 中的所有節點類型實現。這個 Node 接口在JavaScript 中是作為 Node 類型實現的;除了 IE 之外,在其他所有瀏覽器中都可以訪問到這個類型。JavaScript 中的所有節點類型都繼承自 Node 類型,因此所有節點類型都共享著相同的基本屬性和方法。每個節點都有一個 nodeType 屬性,用于表明節點的類型。

(1) nodeName 和 nodeValue 屬性

要了解節點的具體信息,可以使用 nodeName 和 nodeValue 這兩個屬性。這兩個屬性的值完全取決于節點的類型。

(2)節點關系

文檔中所有的節點之間都存在相互關系。

每個節點都有一個 childNodes 屬性,其中保存著一個 NodeList 對象。 NodeList 是一種類數組對象,用于保存一組有序的節點,可以通過位置來訪問這些節點。請注意,雖然可以通過方括號語法來訪問 NodeList 的值,而且這個對象也有 length 屬性,但它并不是 Array 的實例。 NodeList 對象的獨特之處在于,它實際上是基于 DOM 結構動態執行查詢的結果,因此 DOM 結構的變化能夠自動反映在 NodeList 對象中。

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

每個節點都有一個 parentNode 屬性,該屬性指向文檔樹中的父節點。包含在 childNodes 列表中的所有節點都具有相同的父節點,因此它們的 parentNode 屬性都指向同一個節點。
包含在childNodes 列表中的每個節點相互之間都是同胞節點。通過使用列表中每個節點的 previousSibling和 nextSibling 屬性,可以訪問同一列表中的其他節點。列表中第一個節點的 previousSibling 屬性值為 null ,而列表中最后一個節點的 nextSibling 屬性的值同樣也為 null。

if (someNode.nextSibling === null){
    alert("Last node in the parent’s childNodes list.");
} else if (someNode.previousSibling === null){
    alert("First node in the parent’s childNodes list.");
}

所有節點都有的最后一個屬性是 ownerDocument ,該屬性指向表示整個文檔的文檔節點。這種關系表示的是任何節點都屬于它所在的文檔,任何節點都不能同時存在于兩個或更多個文檔中。通過這個屬性,我們可以不必在節點層次中通過層層回溯到達頂端,而是可以直接訪問文檔節點。

(3)操作節點

因為關系指針都是只讀的,所以 DOM 提供了一些操作節點的方法。其中,最常用的方法是appendChild() ,用于向 childNodes 列表的末尾添加一個節點。

使用insertBefore() 方法可以把節點放在 childNodes 列表中某個特定的位置上,接受兩個參數:要插入的節點和作為參照的節點。

2、Document類型

在瀏覽器中, document 對象是 HTMLDocument (繼承自 Document 類型)的一個實例,表示整個 HTML 頁面。
Document 類型可以表示 HTML 頁面或者其他基于 XML 的文檔。不過,最常見的應用還是作為HTMLDocument 實例的 document 對象。通過這個文檔對象,不僅可以取得與頁面有關的信息,而且還能操作頁面的外觀及其底層結構。

(1)文檔的子節點

documentElement屬性,該屬性始終指向 HTML 頁面中的 <html> 元素。作為 HTMLDocument 的實例, document 對象還有一個 body 屬性,直接指向 <body> 元素。

var body = document.body; //取得對<body>的引用

所有瀏覽器都支持 document.documentElement 和 document.body 屬性。

(2)文檔信息

<title> 元素中的文本——顯示在瀏覽器窗口的標題欄或標簽頁上。修改 title 屬性的值不會改變 <title>元素。

//取得文檔標題
var originalTitle = document.title;
//設置文檔標題
document.title = "New page title";

對網頁的請求有關的屬性:URL 、 domain 和 referrer 。

  • URL 屬性中包含頁面完整的 URL(即地址欄中顯示的 URL);
  • domain 屬性中只包含頁面的域名;
  • referrer屬性中保存著鏈接到當前頁面的URL;
//取得完整的 URL
var url = document.URL;
//取得域名
var domain = document.domain;
//取得來源頁面的 URL
var referrer = document.referrer;

(3)查找元素

Document 類型為此提供了兩個方法: getElementById() 和 getElementsByTagName() 。
getElementById() ,接收一個參數:要取得的元素的 ID。如果找到相應的元素則返回該元素,如果不存在帶有相應 ID 的元素,則返回 null 。如果頁面中多個元素的 ID 值相同, getElementById() 只返回文檔中第一次出現的元素。

<div id="myDiv">Some text</div>
var div = document.getElementById("myDiv"); //取得<div>元素的引用

getElementsByTagName(), 接收一個參數:要取得元素的標簽名。返回的是包含零或多個元素的 NodeList 。

var   images = document.getElementsByTagName("img");
alert(images.length); //輸出圖像的數量
alert(images[0].src); //輸出第一個圖像元素的 src 特性
alert(images.item(0).src); //輸出第一個圖像元素的 src 特性

可以使用方括號語法或 item() 方法來訪問 HTMLCollection 對象中的項。

HTMLCollection 對象還有一個方法,叫做 namedItem() ,使用這個方法可以通過元素的 name特性取得集合中的項。

<img src="myimage.gif" name="myImage">
var myImage = images.namedItem("myImage");
var myImage = images["myImage"];    //對命名的項也可以使用方括號語法來訪問

getElementsByName() ,返回帶有給定 name 特性的所有元素。最常使用 getElementsByName() 方法的情況是取得單選按鈕;為了確保發送給瀏覽器的值正確無誤,所有單選按鈕必須具有相同的 name 特性。

 <fieldset>
        <legend>Which color do you prefer?</legend>
        <ul>
            <li>
                <input type="radio" value="red" name="color" id="colorRed">
                <label for="colorRed">Red</label>
            </li>
            <li>
                <input type="radio" value="green" name="color" id="colorGreen">
                <label for="colorGreen">Green</label>
            </li>
            <li>
                <input type="radio" value="blue" name="color" id="colorBlue">
                <label for="colorBlue">Blue</label>
            </li>
        </ul>
</fieldset>

var radios = document.getElementsByName("color");

3、Element類型

Element 類型用于表現 XML或 HTML元素,提供了對元素標簽名、子節點及特性的訪問。
要訪問元素的標簽名,可以使用 nodeName 屬性,也可以使用 tagName 屬性;這兩個屬性會返回相同的值(使用后者主要是為了清晰起見)。

<div id="myDiv"></div>
var div = document.getElementById("myDiv");
alert(div.tagName); //"DIV"
alert(div.tagName == div.nodeName); //true

在 HTML 中,標簽名始終都以全部大寫表示;

(1) HTML 元素

所有 HTML 元素都由 HTMLElement 類型表示或它的子類型來表示。 HTMLElement 類型直接繼承自 Element 并添加了一些屬性。

<div id="myDiv" class="bd" title="Body text" lang="en" dir="ltr"></div>

var div = document.getElementById("myDiv");
//獲取每個屬性的值
alert(div.id); //"myDiv""
alert(div.className); //"bd"
alert(div.title); //"Body text"
alert(div.lang); //"en"
alert(div.dir); //"ltr"

//為每個屬性賦予新的值
div.id = "someOtherId";
div.className = "ft";
div.title = "Some other text";
div.lang = "fr";
div.dir ="rtl";

(2)取得特性

每個元素都有一或多個特性,這些特性的用途是給出相應元素或其內容的附加信息。操作特性的DOM 方法主要有三個,分別是 getAttribute() 、 setAttribute() 和 removeAttribute() 。這三個方法可以針對任何特性使用,包括那些以 HTMLElement 類型屬性的形式定義的特性。

var div = document.getElementById("myDiv");
alert(div.getAttribute("id")); //"myDiv"
alert(div.getAttribute("class")); //"bd"
alert(div.getAttribute("title")); //"Body text"
alert(div.getAttribute("lang")); //"en"
alert(div.getAttribute("dir")); //"ltr"

如果給定名稱的特性不存在, getAttribute() 返回 null 。

通過 getAttribute() 方法也可以取得自定義特性。

<div id="myDiv" my_special_attribute="hello!"></div>
//包含一個名為 my_special_attribute 的自定義特性,它的值是 "hello!"
var value = div.getAttribute("my_special_attribute");

特性的名稱是不區分大小寫的,即 "ID" 和 "id" 代表的都是同一個特性。
根據 HTML5 規范,自定義特性應該加上 data- 前綴以便驗證。

(3)設置特性

setAttribute() 會以指定的值替換現有的值;如果特性不存在,setAttribute()則創建該屬性并設置相應的值。

div.setAttribute("id", "someOtherId");
div.setAttribute("class", "ft");
div.setAttribute("title", "Some other text");
div.setAttribute("lang","fr");
div.setAttribute("dir", "rtl");

通過 setAttribute() 方法既可以操作 HTML 特性也可以操作自定義特性。通過這個方法設置的特性名會被統一轉換為小寫形式,即 "ID" 最終會變成 "id" 。

因為所有特性都是屬性,所以直接給屬性賦值可以設置特性的值。為 DOM 元素添加一個自定義的屬性,該屬性不會自動成為元素的特性。

div.id = "someOtherId";
div.align = "left";

div.mycolor = "red";
alert(div.getAttribute("mycolor")); //null(IE 除外)

removeAttribute()用于徹底刪除元素的特性。調用這個方法不僅會清除特性的值,而且也會從元素中完全刪除特性。

div.removeAttribute("class");

(4) attributes 屬性

Element 類型是使用 attributes 屬性的唯一一個 DOM節點類型。 attributes 屬性中包含一個NamedNodeMap ,與 NodeList 類似,也是一個“動態”的集合。元素的每一個特性都由一個 Attr 節點表示,每個節點都保存在 NamedNodeMap 對象中。 NamedNodeMap 對象擁有下列方法。

  • getNamedItem(name) :返回 nodeName 屬性等于 name 的節點;
  • removeNamedItem(name) :從列表中移除 nodeName 屬性等于 name 的節點;
  • setNamedItem(node) :向列表中添加節點,以節點的 nodeName 屬性為索引;
  • item(pos) :返回位于數字 pos 位置處的節點。

attributes 屬性中包含一系列節點,每個節點的 nodeName 就是特性的名稱,而節點的 nodeValue就是特性的值。

var id = element.attributes.getNamedItem("id").nodeValue;
//使用方括號語法通過特性名稱訪問節點的簡寫方式
var id = element.attributes["id"].nodeValue;

也可以使用這種語法來設置特性的值,即先取得特性節點,然后再將其 nodeValue 設置為新值。

//設置特性的值
element.attributes["id"].nodeValue = "someOtherId";
//刪除具有給定名稱的特性
var oldAttr = element.attributes.removeNamedItem("id");
//為元素添加一個新特性
element.attributes.setNamedItem(newAttr);

(5)創建元素

使用 document.createElement() 方法可以創建新元素。

var div = document.createElement("div");
//操作元素的特性,為它添加更多子節點
div.id = "myNewDiv";
div.className = "box";
//把新元素添加到文檔樹
document.body.appendChild(div);

//以另一種方式使用 createElement()
var div = document.createElement("<div id=\"myNewDiv\" class=\"box\"></div >");

在新元素上設置這些特性只是給它們賦予了相應的信息。由于新元素尚未被添加到文檔樹中,因此設置這些特性不會影響瀏覽器的顯示。要把新元素添加到文檔樹,可以使用 appendChild() 、 insertBefore() 或replaceChild() 方法。

(6)元素的子節點

元素可以有任意數目的子節點和后代節點,因為元素可以是其他元素的子節點。元素的childNodes 屬性中包含了它的所有子節點,這些子節點有可能是元素、文本節點、注釋或處理指令。

4、Text類型

文本節點由 Text 類型表示,包含的是可以照字面解釋的純文本內容。純文本中可以包含轉義后的HTML 字符,但不能包含 HTML 代碼。

(1)創建文本節點

可以使用 document.createTextNode() 創建新文本節點,這個方法接受一個參數——要插入節點中的文本。

var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);
document.body.appendChild(element);

(2)規范化文本節點

normalize()將相鄰文本節點合并的方法。這個方法是由 Node 類型定義的(因而在所有節點類型中都存在)。

var element = document.createElement("div");
element.className = "message";
var textNode = document.createTextNode("Hello world!");
element.appendChild(textNode);

var anotherTextNode = document.createTextNode("Yippee!");
element.appendChild(anotherTextNode);

document.body.appendChild(element);

alert(element.childNodes.length); //2

element.normalize();
alert(element.childNodes.length); //1
alert(element.firstChild.nodeValue); // "Hello world!Yippee!"

(3)分割文本節點

splitText() 將一個文本節點分成兩個文本節點。
原來的文本節點將包含從開始到指定位置之前的內容,新文本節點將包含剩下的文本。這個方法會返回一個新文本節點,該節點與原節點的parentNode 相同。

var element = document.createElement("div");
element.className = "message";

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

var newNode = element.firstChild.splitText(5);
alert(element.firstChild.nodeValue); //"Hello"
alert(newNode.nodeValue); //" world!"
alert(element.childNodes.length); //2

分割文本節點是從文本節點中提取數據的一種常用 DOM解析技術。

5、Comment類型

注釋在 DOM 中是通過 Comment 類型來表示的。
Comment 類型與 Text 類型繼承自相同的基類,因此它擁有除 splitText() 之外的所有字符串操作方法。

6、CDATASection類型

CDATASection 類型只針對基于 XML 的文檔,表示的是 CDATA 區域。與 Comment 類似,CDATASection 類型繼承自 Text 類型,因此擁有除splitText() 之外的所有字符串操作方法。

二、DOM操作技術

1、動態腳本

創建動態腳本也有兩種方式:插入外部文件和直接插入 JavaScript 代碼。

//動態加載的外部 JavaScript 文件
<script type="text/javascript" src="client.js"></script>
//創建節點的 DOM 代碼
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "client.js";
document.body.appendChild(script);
//使用函數來封裝
function loadScript(url){
    var script = document.createElement("script");
    script.type = "text/javascript";
    script.src = url;
    document.body.appendChild(script);
}

//調用
loadScript("client.js");

2、動態樣式

能夠把 CSS 樣式包含到 HTML 頁面中的元素有兩個。其中, <link> 元素用于包含來自外部的文件,而 <style> 元素用于指定嵌入的樣式。
所謂動態樣式是指在頁面剛加載時不存在的樣式;動態樣式是在頁面加載完成后動態添加到頁面中的。

//引用
<link rel="stylesheet" type="text/css" href="styles.css">
//動態創建
var link = document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = "style.css";
var head = document.getElementsByTagName("head")[0];
head.appendChild(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("styles.css");

必須將 <link> 元素添加到 <head>而不是 <body> 元素,才能保證在所有瀏覽器中的行為一致。

3、操作表格

<table> 元素是 HTML 中最復雜的結構之一。要想創建表格,一般都必須涉及表示表格行、單元格、表頭等方面的標簽。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • ??DOM(文檔對象模型)是針對 HTML 和 XML 文檔的一個 API(應用程序編程接口)。 ??DOM 描繪...
    霜天曉閱讀 3,674評論 0 7
  • ??DOM 1 級主要定義的是 HTML 和 XML 文檔的底層結構。 ??DOM2 和 DOM3 級則在這個結構...
    霜天曉閱讀 1,468評論 1 3
  • 之前通過深入學習DOM的相關知識,看了慕課網DOM探索之基礎詳解篇這個視頻(在最近看第三遍的時候,準備記錄一點東西...
    微醺歲月閱讀 4,504評論 2 61
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標簽默認的外補...
    _Yfling閱讀 13,776評論 1 92
  • ??JavaScript 與 HTML 之間的交互是通過事件實現的。 ??事件,就是文檔或瀏覽器窗口中發生的一些特...
    霜天曉閱讀 3,516評論 1 11