JavaScript DOM 基礎知識點

《JavaScript DOM 編程藝術 》 《JavaScript 高級程序設計》

平穩退化和漸進增強

在 JavaScript DOM 編程藝術一書中,個人認爲,最核心的思想是作者提到的平穩退化和漸進增強。

所謂的平穩退化,就是讓JS代碼適應所有的用戶,這是一個基礎,不管用戶處於什麼環境,都要爲用戶提供最基本的可訪問性。

而漸進增強則是爲高級用戶提供更好的體驗效果,利用JS去包裝原始的HTML數據,但前提是JS只是一個行爲層,必須與結構層分離。

也就是說在平穩退化的基礎上漸進增強,而漸進增強的結果一般都是符合平穩退化的。

DOM

JavaScript 主要由3部分組成,也就是 ECMAScript,DOM,BOM。

作爲 JavaScript 的重要組成部分,DOM 的全稱是 Document Object Model,即是文檔對象模型。用類似於家譜的樹形結構來表示 DOM 再適合不過了,而組成這個 DOM Tree 的就是節點。


節點——Node 類型

DOM1 定義了一個 Node 接口,該接口由 DOM 中所有的節點類型實現,而在 JavaScript 中,該接口作爲 Node 類型實現,所有的節點類型都繼承自 Node 類型。
Node 類型主要由四個屬性,包括 nodeType、nodeName、nodeValue 和 childNodes。

nodeType 屬性

所有節點都有一個 nodeType 屬性,表示該節點的類型。

DOM 中定義了12中 Node 類型,其中主要有3種節點:元素節點、文本節點、文檔節點。

元素節點的 nodeType 屬性值爲 Node.ELEMENT_NODE 或 1。

文本節點的 nodeType 屬性值爲 Node.TEXT_NODE 或 3。

文檔節點的 nodeType 屬性值爲 Node.DOCUMENT_NODE 或 9。

注:爲了跨瀏覽器,一般使用數值表示 nodeType 屬性。

nodeName 屬性和 nodeValue 屬性

對於元素節點,nodeName 屬性保存的是元素的標籤名,nodeValue 屬性始終爲 null。

childNodes 屬性

該屬性中保存一個 NodeList 對象。
訪問:someNode.childNodes[i]; 等價於 someNode.childNode.item(i);
注:空格、換行、製表,這些空白符會產生空白的文本節點!!!除了 IE9-
關於 NodeList 對象
NodeList 對象是一種類數組對象,並非 Array 的實例,並且根據 DOM 結構的變化自動變化。
NodeList 轉化爲數組的方法:(arguments 對象也是採用該方法)
function convert2Array(nodes){
    var array = null;
    try{
        //針對非IE瀏覽器
        array = Array.prototype.slice.call(nodes, 0);
    }
    //IE8-瀏覽器會捕獲錯誤
    catch(e){
        array = new Array();
        for(var i = 0, len = nodes.length ; i < len ; i ++){
            array.push(nodes[i]);
        }
    }
    return array;
}

parentNode 屬性、previousSibling 屬性、nextSibling 屬性、firstChild 屬性、lastChild 屬性 和 hasChildNodes() 方法

appendChild() 方法、insertBefore() 方法、replaceChild() 方法 和 removeChild() 方法

/*
原有的 html 結構:
<div id="a">
    <div id="b"></div>
</div>
*/

var a = document.getElementById("a");
//若已經創造了新的節點 c
var newNode = a.appendChild(c);
alert(newNode == c); //true

/*
此時 html 結構爲
<div id="a">
    <div id="b"></div>
    <div id="c"></div>
</div>
*/
//若新插入的節點已存在,appendChild 則會改變原來的位置爲當前位置

var newNode = a.insertBefore(d,b);
alert(newNode == d); //true

/*
此時 html 結構爲
<div id="a">
    <div id="d"></div>
    <div id="b"></div>
    <div id="c"></div>
</div>
*/

var newNode = a.replace(e,d);
alert(newNode == e); //tue

/*
此時 html 結構爲
<div id="a">
    <div id="e"></div>
    <div id="b"></div>
    <div id="c"></div>
</div>
*/

var removeNode = a.removeChild(e);
alert(removeNode == e);//true

/*
此時 html 結構爲
<div id="a">
    <div id="b"></div>
    <div id="c"></div>
</div>
*/

自定義 insertAfter() 方法

DOM 中沒有提供 insertAfter() 方法,但我們可以自己定義:
function insertAfter(newNode, targetNode){
    var parent = targetNode.parent;
    if(parent.lastChild == targetNode){
        parent.appendChild(newNode);
    }
    else{
        parent.insertBefore(newNode, targetNode.previousSibling);
    }
}

文檔節點——Document 類型

JavaScript 通過 Document 類型表示文檔,其子類 HTMLDocument 在瀏覽器中的一個實例對象是 document。

nodeType 值爲 9
nodeName 值爲 "#document"
nodeValue 值爲 null
parentNode 值爲 null

document 對象

documentElement 屬性:取得 <html> 元素。document.documentElement;
body 屬性:取得 <body> 元素。document.body;
title 屬性:可讀寫文檔的標題。document.title;
URL 屬性:只讀頁面完整的URL。document.URL; 相當於 window.location; 或 location.href;
domain 屬性:可讀寫域名,但設值時有限制,若 URL 中含子域名,則只能設爲該 URL 的高層域名。document.domain;
referrer 屬性:只讀頁面的來源,即是鏈接到當前頁面的那個頁面的 URL,所以可能值爲 null。document.referrer;
查找元素:
getElementById() 方法:
按照元素的 id 值返回一個元素節點的對象

注:按照平穩退化漸進增強的原則,使用前做出判斷,如

if(!document.getElementById){
    return false;
}
var link = document.getElementById("a");
注意:在 IE8- 中不區分 id 的大小寫,其他會區分。在 IE7- 中,會匹配表單中的 name 屬性,所以表單的 name 和 id 不要設相同的值。

getElementsByTagName
按照元素的標籤名返回一個 HTMLCollection 對象,類似於 NodeList
var links = document.getElementsByTagName("a");
for(var i = 0 ; i < links.length ; i ++){
    alert(links[i].title);
}

getElementsByClassName

HTML5 DOM 中新增的一個方法,按照元素的 class 值返回一個 HTMLCollection 對象,可查找帶有多個類名的元素,且類名順序不會有影響

var links = document.getElementsByClassName("link item");
alert(links.length);


其他 HTMLCollection 對象:
document.anchors :返回所有帶 name 屬性的 <a>
document.links :返回所有帶 href 屬性的 <a>
document.forms :返回所有 <form> 元素節點
document.images :返回所有 <img> 元素節點


元素節點——Element 類型

元素節點在 HTML 中就是各種標籤,比如 <p>

nodeType 值爲:1
nodeName 值爲:元素的標籤名
nodeValue 值爲:null
注:nodeName 值通常爲大寫,所以比較的時候最好使用 toLowerCase() 方法進行處理。

常用屬性:id、title、className

屬性操作

getAttribute
返回查詢的屬性的值
if(!document.getElementById){
    return false;
}
var link = document.getElementById("item");
alert(link.getAttribute("src"));
link.getAttribute("src") 相當於 link.src,也就是直接採用 DOM 對象直接訪問。
setAttribute
設置屬性的值
var links = document.getElementsByTagName("a");
for(var i = 0 ; i < links.length ; i ++){
    links[i].setAttribute("title","title"+i);
}

links[i].setAttibute("title","title"+i) 相當於 links[i].title = "title" + i;

removeAttribute

移除屬性的值

var link = document.getElementById("item");
link.removeAttribute("title");
注:IE6- 不支持

創建元素——document.ceateElement()

返回創建的新元素的對象。
注:對象創建後並不會在 DOM 樹中,必須將其添加進去,如 appendChild 等。
IE7- 動態創建元素存在的問題:
1)動態創建的 <iframe> 無法設置 name 屬性。
2)動態創建的 <input> 無法使用 reset() 方法。
3)動態創建的 <button> type 值爲 reset 的,無法重設表單。
4)動態創建的單選按鈕,即使 name 值一樣,它們之間沒有關係。
上述問題解決方法如下:
if(client.browser.ie && client.browser.ie <= 7){
    var iframe = document.createElement("<iframe name=\"myframe\"></iframe>");
    var input = document.createElement("<input type=\"checkbox\" />");
    var button = document.createElement("<button type=\"reset\"></button>");
    var radio1 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"1\" />");
    var radio2 = document.createElement("<input type=\"radio\" name=\"choice\" value=\"2\" />");
}
注:其他瀏覽器不支持此寫法,所以要檢測瀏覽器。

文本節點——Text 類型

純文本內容。
nodeType 值爲:3
nodeName 值爲:“#text”
nodeValue 值爲:文本內容
沒有子結點!

length 屬性:保存節點中字節的數目

創建文本節點 document.createTextNode()

返回新創建的文本節點
若一個元素中創建了多個文本節點,則這些文本節點的顯示會連在一起,但是實際卻不是一個節點。可以使用 normalize() 方法將這些文本節點連接爲一個節點。
var p = document.getElementById("text");
var txt1 = document.createTextNode("hello ");
var txt2 = document.createTextNode("word!");
p.appendChild(txt1);
p.appendChild(txt2);
alert(p.childNodes.length); //2
p.normalize();
alert(p.childNodes.length); //1

文檔片段——DocumentFragment 類型

文檔片段可以包含和控制節點,但不會佔用資源,也就是文檔片段中的節點並不會存在 DOM 樹中。利用這點,我們在動態創建節點的時候可以利用文檔片段來優化性能。
文檔片段的創建:document.createDocumentFragment()
var fragment = document.createDocumentFragment();
var ul = document.getElementById("list");
var li = null;
for(var i = 0 ; i < 5 ; i ++){
    li = document.createElement("li");
    li.appendChild(document.createTextNode("item"+i));
    fragment.appendChild(li);
}
ul.appendChild(fragment);
避免了 for 循環中一直爲 ul 添加子節點而造成頁面的反覆渲染。


發佈了22 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章