深刻理解JavaScript系列(23):JavaScript與DOM(上)——也適用於新手

文檔對象模型Document Object Model

DOM(Document Object Model,文檔對象模型)是一個經過和JavaScript進行內容交互的API。Javascript和DOM通常常常做爲一個總體,由於Javascript一般都是用來進行DOM操做和交互的。



主要內容來自:http://net.tutsplus.com/tutorials/javascript-ajax/javascript-and-the-dom-series-lesson-1/

關於DOM,有些知識須要注意:
1. window對象做爲全局對象,也就是說你能夠經過window來訪問全局對象。
 屬性在對象下面以變量的形式存放,在頁面上建立的全部全局對象都會變成window對象的屬性。
方法在對象下面以函數的形式存放,由於左右的函數都存放在window對象下面,因此他們也能夠稱爲方法。

2. DOM爲web文檔建立帶有層級的結果,這些層級是經過node節點組成,這裏有幾種DOM node類型,最重要的是Element, Text, Document。
 Element節點在頁面裏展現的是一個元素,因此若是你有段落元素(<p>),你能夠經過這個DOM節點來訪問。
 Text節點在頁面裏展現的全部文本相關的元素,因此若是你的段落有文本在裏面的話,你能夠直接經過DOM的Text節點來訪問這個文本
 Document節點表明是整個文檔,它是DOM的根節點。

3. 每一個引擎對DOM標準的實現有一些輕微的不一樣。例如,Firefox瀏覽器使用的Gecko引擎有着很好的實現(儘管沒有徹底遵照W3C規範),但IE瀏覽器使用的Trident引擎的實現卻不完整並且還有bug,給開發人言帶來了不少問題。

若是你正在使用Firefox,我推薦你當即下載Firebug插件,對於你瞭解DOM結構很是有用。

Web上的JavaScript

Script元素

當你在網站頁面上使用JavaScript的時候,須要使用SCRIPT元素:

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
    <html xmlns="http://www.w3.org/1999/xhtml" lang="en">  
        <head>  
                <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
                <title>JavaScript!</title>  
        </head>  
        <body>        
            <script type="text/javascript">  
            // <![CDATA[  
      
            // ]]>  
            </script>        
        </body>  
    </html>  

上述代碼,嚴格來講SCRIPT的TYPE屬性應該設置爲application/javascript,可是因爲IE不支持這個,因此平時咱們不得不寫成text/javascript或者直接去掉type。另外你也能夠看到在SCRIPT元素裏的註釋行// <![CDATA[ 是用來告訴支持XHTML的瀏覽器,這裏面的代碼是字符數據而不是XHTML標籤,好比若是你在裏面的數據使用了<或>,瀏覽器就不會再解析成XHTML標籤了。

Defer屬性

任何在SCRIPT元素裏聲明的代碼在頁面加載的時候都會運行,惟一一個例外是給SCRIPT元素加上一個defer屬性。defer屬性告訴瀏覽器加載完HTML文檔之後再執行JS代碼,但這個屬性只能在IE下使用。

鏈接外部腳本

若是你想了解外部腳本,只須要簡單地在SCRIPT上使用SRC屬性就好了,使用單獨的JS文件的好處是能夠緩存,並且也不須要擔憂CDATA方面的問題:

<script type="text/javascript" src="my-script.js"></script>

JavaScript必備

在咱們繼續DOM以前,咱們來複習一下JavaScript的核心必備知識,若是你還不瞭解,也不要緊,咱們在這一章節將稍微花點時間來回顧一下。

JavaScript有幾種數據類型:Number, String, Boolean, Object, Undefined and Null。

單行註釋使用雙斜槓//,雙斜槓後面的全部文字都會被註釋掉,多行注意使用/*和*/括住。

Number

在JavaScript裏全部的Number都是浮點型的,當聲明一個數字變量的時候,記得不要使用任何引號。

// 注:使用var類聲明變量
var leftSide = 100;  
var topSide = 50;  
var areaOfRectangle = leftSide * topSide; // = 5000  

String

JavaScript裏聲明字符串特別簡單,和其它語言同樣,在JS裏使用單引號或雙引號均可以。

var firstPart = 'Hello';  
var secondPart = 'World!';  
var allOfIt = firstPart + ' ' + secondPart; // Hello World!  
// +符合是字符鏈接符。也用於數字相加

Boolean

布爾類型用於條件判斷,布爾類型是隻有2個值:true和false。任何使用邏輯操做符的比較都會返回布爾值。

5 === (3 + 2); // = true  
// 你也能夠將布爾值賦給一個變量
var veryTired = true;
// 這樣使用
if (veryTired) {
    // 執行代碼 
}   

===也是比較操做符,不只比較數值,還比較類型。

Function

函數是特殊的對象。

// 使用function操做符來聲明新函數  
function myFunctionName(arg1, arg2) {
    // 函數代碼
}

// 你也能夠聲明匿名函數 
function (arg1, arg2) {
    // Function code goes here.  
}

// 運行函數很簡單,直接在函數名稱後面加上小括號就能夠了
// 或者也能夠帶上參數
myFunctionName(); // 無參
myFunctionName('foo', 'bar'); // 有參數

// 也可使用自調用  

(function () {
    // 這裏自調用函數
})();

Array

數組也是特殊的對象,它包含了一批值(或對象),訪問這些數據的話須要使用數字索引:

// 2種方式聲明數組

// 字面量:  
var fruit = ['apple', 'lemon', 'banana'];

// Array構造函數:  
var fruit = new Array('apple', 'lemon', 'banana');

fruit[0]; // 訪問第1個項(apple)  
fruit[1]; // 訪問第2個項(lemon)  
fruit[2]; // 訪問第3個項(banana) 

Object

一個對象是一個key-value的集合,和數組類似,惟一的不一樣是你能夠爲每一個數據定義一個名稱。

// 2種類型定義Object對象

// 字面量(大括號)
var profile = {
    name: 'Bob',
    age: 99,
    job: 'Freelance Hitman'
};

// 使用Object構造函數
var profile = new Object();
profile.name = 'Bob';
profile.age = 99;
profile.job = 'Freelance Hitman';  

IF/Else語句

JS裏使用最多的語句莫過於條件語句了:

var legalDrinkingAge = 21;  
var yourAge = 29;  
  
if ( yourAge >= legalDrinkingAge ) {   
    alert('You can drink.');  
} else {  
    alert('Sorry, you cannot drink.');  

JavaScript操做符

建議你訪問這個頁面來查看全部的JS操做符,這裏我僅僅給出一些例子:   

// 加減乘除
var someMaths = 2 + 3 + 4 - 10 * 100 / 2;  
      
// 等於  
if ( 2 == (5 - 3 ) { /* 代碼 */ } // == 比較是否相等
      
// 不等於 
if ( 2 != (5 - 3 ) { /* 代碼 */ }   
      
// 嚴格等於(推薦) 
2 === 2 // 代替 2 == 2  
2 !== 3 // 代替 2 != 3  
      
// 賦值:  
var numberOfFruit = 9;  
numberOfFruit -= 2; // 等價於 "numberOfFruit = numberOfFruit - 2"  
numberOfFruit += 2; // 等價於 "numberOfFruit = numberOfFruit + 2"   

Loop循環

Loop循環在是遍歷數組或者對象的全部成員的時候很是方便,JavaScript裏使用最多的是FOR和WHILE語句。

var envatoTutSites = ['NETTUTS', 'PSDTUTS', 'AUDIOTUTS', 'AETUTS', 'VECTORTUTS'];

// WHILE循環
var counter = 0;
var lengthOfArray = envatoTutSites.length;
while (counter < lengthOfArray) {
    alert(envatoTutSites[counter]);
    counter++; // 等價於counter += 1;  
}

// FOR循環
// i只是用於迭代,能夠任意取名 
for (var i = 0, length = envatoTutSites.length; i < length; i++) {
    alert(envatoTutSites[i]);
}  

DOM正文

訪問DOM節點

咱們來個例子,一個HTML裏包含一段文本和一個無序的列表。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">  
    <head>  
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />  
            <title>JavaScript!</title>  
    </head>  
    <body>  
  
        <p id="intro">My first paragraph...</p>  
  
        <ul>  
            <li>List item 1</li>  
            <li>List item 1</li>  
            <li>List item 1</li>  
            <li>List item 1</li>  
            <li>List item 1</li>  
        </ul>  
  
        <script type="text/javascript">  
        // <![CDATA[  
  
        // ]]>  
</script>  
  
    </body>  
</html> 

上面例子裏,咱們使用getElementById DOM方法來訪問p段落,在SCRIPT裏添加以下代碼:

var introParagraph = document.getElementById('intro');  
// 如今有了該DOM節點,這個DOM節點展現的是該信息段落

變量introParagraph如今已經引用到該DOM節點上了,咱們能夠對該節點作不少事情,好比查詢內容和屬性,或者其它任何操做,甚至能夠刪除它,克隆它,或者將它移到到DOM樹的其它節點上。

文檔上的任何內容,咱們均可以使用JavaScript和DOM API來訪問,因此相似地,咱們也能夠訪問上面的無序列表,惟一的問題是該元素沒有ID屬性,若是ID的話就可使用相同的方式,或者使用以下getElementsByTagName方式:

var allUnorderedLists = document.getElementsByTagName('ul');  
// 'getElementsByTagName'返回的是一個節點集合
// - 和數組有點類似

getElementsByTagName

getElementsByTagName方法返回的是一個節點集合,和數組相似也有length屬性,重要的一個特性是他是live的——若是你在該元素裏添加一個新的li元素,這個集合就會自動更新,介於他和數組類型,因此能夠和訪問數組同樣的方法來訪問,因此從0開始:

// 訪問無序列表: [0]索引
var unorderedList = document.getElementsByTagName('ul')[0];

// 獲取全部的li集合:  
var allListItems = unorderedList.getElementsByTagName('li');

// 循環遍歷
for (var i = 0, length = allListItems.length; i < length; i++) {
    // 彈出該節點的text內容
    alert(allListItems[i].firstChild.data);
} 

如下圖例更清晰地展現了DOM獲取的知識:



DOM穿梭

「穿梭」這個詞主要是用來描述經過DOM查找節點,DOM API提供了大量的節點屬性讓咱們來往上或者往下查詢節點。

全部的節點都有這些屬性,都是能夠用於訪問相關的node節點:
Node.childNodes: 訪問一個單元素下全部的直接子節點元素,能夠是一個可循環的類數組對象。該節點集合能夠保護不一樣的類型的子節點(好比text節點或其餘元素節點)。
Node.firstChild: 與‘childNodes’數組的第一個項(‘Element.childNodes[0]‘)是一樣的效果,僅僅是快捷方式。
Node.lastChild: 與‘childNodes’數組的最後一個項(‘Element.childNodes[Element.childNodes.length-1]‘)是一樣的效果,僅僅是快捷方式。shortcut.
Node.parentNode: 訪問當前節點的父節點,父節點只能有一個,祖節點能夠用‘Node.parentNode.parentNode’的形式來訪問。
Node.nextSibling: 訪問DOM樹上與當前節點同級別的下一個節點。
Node.previousSibling: 訪問DOM樹上與當前節點同級別的上一個節點。



經過這張圖,理解起來就簡單多了,但有個很是重要的知識點:那就是元素之間不能有空格,若是ul和li之間有空格的話,就會被認爲是內容爲空的text node節點,這樣ul.childNodes[0]就不是第一個li元素了。相應地,<p>的下一個節點也不是<ul>,由於<p>和<ul>之間有一個空行的節點,通常遇到這種狀況須要遍歷全部的子節點而後判斷nodeType類型,1是元素,2是屬性,3是text節點,詳細的type類型能夠經過此地址:

    Node.ELEMENT_NODE == 1
    Node.ATTRIBUTE_NODE == 2
    Node.TEXT_NODE == 3
    Node.CDATA_SECTION_NODE == 4
    Node.ENTITY_REFERENCE_NODE == 5
    Node.ENTITY_NODE == 6
    Node.PROCESSING_INSTRUCTION_NODE == 7
    Node.COMMENT_NODE == 8
    Node.DOCUMENT_NODE == 9
    Node.DOCUMENT_TYPE_NODE == 10
    Node.DOCUMENT_FRAGMENT_NODE == 11
    Node.NOTATION_NODE == 12

總結

原生的DOM方法和屬性足夠咱們平常的應用了,本章節咱們只列舉了一些例子,下一章節咱們列舉更多的例子,還會包括瀏覽器事件模型。

同步與推薦

本文已同步至目錄索引:深刻理解JavaScript系列

深刻理解JavaScript系列文章,包括了原創,翻譯,轉載等各種型的文章,若是對你有用,請推薦支持一把,給大叔寫做的動力。
相關文章
相關標籤/搜索