1. 相關(guān)概念
由 W3C 批準(zhǔn)并由所有于標(biāo)準(zhǔn)相兼容的 Web 瀏覽器支持的第三方技術(shù)成為 DOM (文檔對象模型)??梢岳?DOM 改善文檔的可交互性,就像利用 CSS 給文檔添加各種樣式一樣。
JS:是一種腳本語言,JS 腳本通常只能通過 Web 瀏覽器去完成某種操作而不是獨(dú)立運(yùn)行。JS 提供了一種操控 Web 瀏覽器的手段,例如,JS 語言可以用來調(diào)整瀏覽器窗口的高度、寬度和屏顯位置等屬性。以這種辦法給 Web 瀏覽器本身的屬性可以看做是 BOM (瀏覽器對象模型)。
DOM : Document Object Model,文檔對象模型。簡單的說 DOM 是一套對文檔的內(nèi)容進(jìn)行抽象和概念化的方法。
JS 早期版本提供了對 Web 文檔的某些實(shí)際內(nèi)容(主要是圖像和表單)進(jìn)行查詢和操控的手段。JS 語言本身也預(yù)先定義了 "images" 和 "forms" 等關(guān)鍵字。—— 這種試驗(yàn)性質(zhì)的初級(jí) DOM 被稱為 “第 0 級(jí) DOM ”( DOM Level 0)。在形成標(biāo)準(zhǔn)之前,常見的用法包括對圖像進(jìn)行鏈接和顯示以及在客戶端進(jìn)行某種形式的數(shù)據(jù)合法性驗(yàn)證。
-
DHTML( dynamic HTML)
- 利用 HTML 將網(wǎng)頁標(biāo)記為各種元素
- 利用 CSS 設(shè)計(jì)各有關(guān)元素的排版樣式并確定它們在窗口中的顯示位置
- 利用 JS 實(shí)時(shí)操控和改變各種有關(guān)樣式
DOM Level 1:為解決瀏覽器的不兼容問題而制定的標(biāo)準(zhǔn)化 DOM —— 可以讓任何一種程序設(shè)計(jì)語言對使用任何一種標(biāo)記語言編寫出來的任何文檔進(jìn)行控制
DOM 是一種 API:一個(gè)與系統(tǒng)平臺(tái)和編程語言無關(guān)的接口,程序和腳本可以通過這個(gè)接口動(dòng)態(tài)的對文檔的內(nèi)容、結(jié)構(gòu)和樣式進(jìn)行訪問和修改。
2. JS 語法
-
用 JS 編寫的代碼必須嵌在一份 HTML/XHTML 文檔中才能執(zhí)行??梢酝ㄟ^兩種方法做到:
- 將 JS 代碼插入到文檔
<head>
部分的<script>
間 - 將 JS 代碼保存在獨(dú)立的文件 —— 以
.js
為文件的擴(kuò)展名,再利用<script>
標(biāo)簽的 src 屬性指向該文件
- 將 JS 代碼插入到文檔
JS 是解釋型語言,Web 瀏覽器將負(fù)責(zé)完成有關(guān)的解釋和執(zhí)行工作。瀏覽器中的 JS 解釋器將直接讀如源代碼并加以執(zhí)行。
語句
每條語句的末尾加上一個(gè)分號(hào)用于分隔
使用
//
作為注釋的開頭;多行注釋使用/* ...... */
;HTML 風(fēng)格注釋<!-
在 JS 中僅適用于單行注釋,對于->
HTML 必須使用其來結(jié)束注釋,但 JS 不要求,它會(huì)把其視為注釋內(nèi)容的一部分(建議不使用這種注釋)變量
建議在對變量賦值之前進(jìn)行聲明:
var mood, age;
或聲明和賦值同時(shí)進(jìn)行:
var mood = "happy", age = 33;
JS 中變量和其他語法元素的名字區(qū)分大小寫,不允許變量名包含空格或標(biāo)點(diǎn)符號(hào)(
$
例外)數(shù)據(jù)類型
字符串:由零個(gè)或多個(gè)字符構(gòu)成,字符包括字母、數(shù)字、標(biāo)點(diǎn)符號(hào)和空格。字符串必須放在引號(hào)中——單雙引號(hào)均可。
\
表示轉(zhuǎn)義符數(shù)值:數(shù)值可以是任意位數(shù),整數(shù)、浮點(diǎn)數(shù),負(fù)數(shù)
布爾值:
true
或false
。字符串、數(shù)值和布爾值都屬于離散值 —— 在任意時(shí)刻只能有一個(gè)值。
數(shù)組
數(shù)組是由名字相同的多個(gè)值構(gòu)成的一個(gè)集合, 集合中的每個(gè)值都是這個(gè)數(shù)組的元素。
使用
Array
聲明,聲明時(shí)可以對數(shù)組的元素個(gè)數(shù)進(jìn)行限定:var beatles = Array(4);
(并非必須)數(shù)組中元素存放位置使用下標(biāo)
index
給出:array[index] = element;
下標(biāo)從 0 開始向數(shù)組中添加元素:
beatles[0] = 'John';
數(shù)組中的元素可以是任意數(shù)據(jù)類型var beatles = Array("John", "Paul", "George", "Ringo");
<==>var beatles = ["John", "Paul", "George", "Ringo"];
-
關(guān)聯(lián)數(shù)組:為每個(gè)元素明確的給出下標(biāo)的方式來創(chuàng)建關(guān)聯(lián)數(shù)組
var lennon = Array();
lennon["name"] = "John";
lennon["year"] = 1940;
lennon["living"] = false;
```
操作
算術(shù)操作符:
+
、-
、*
、/
等;++
、--
、+=
條件語句
-
if ... else ... 語句
if(conditon){ statements; }else { statements; }
比較操作符:
>
、<
、>=
、<=
、==
、!=
邏輯操作符:
&&
、||
、!
、!
循環(huán)語句
-
while
while(condition){ statements; }
-
do-while:對循環(huán)控制條件的求值發(fā)生在每次循環(huán)結(jié)束之后,因此即使循環(huán)控制條件的首次求值結(jié)果是 false,也會(huì)執(zhí)行一次。
do{ statements; }while(condition);
-
for
for(initial condition; test condition; alter condition){ statements; }
函數(shù)
-
函數(shù)即一組允許人們在代碼里隨時(shí)調(diào)用的語句。從效果上看,每個(gè)函數(shù)都相當(dāng)于一個(gè)短小的腳本。
function name(arguments){ statements; }
函數(shù)可以接受參數(shù)來完成指定的數(shù)據(jù)操作。JS 提供了許多內(nèi)置函數(shù)。
函數(shù)可以由返回值,使用
return
函數(shù)可以當(dāng)作是一種數(shù)據(jù)類型來使用,因此可以把一個(gè)函數(shù)的調(diào)用結(jié)果賦值給一個(gè)變量
變量的作用域:如果在某個(gè)函數(shù)中使用了
var
,變量被視為一個(gè)局部變量,否則為全局變量 —— 覆蓋所有與之同名的變量。對象
-
對象是自我包含的數(shù)據(jù)集合,包含在對象里的數(shù)據(jù)可以通過兩種形式 —— 屬性 和 方法 訪問
- 屬性是隸屬于某個(gè)特定對象的變量
- 方法是只有某個(gè)特定對象才能調(diào)用的函數(shù)
-
屬性和方法都需要使用
.
來訪問。
Object.property
Object.method()
```
- 實(shí)例是對象的具體表現(xiàn)形式:對象是統(tǒng)稱,實(shí)例是個(gè)體。為給定對象創(chuàng)建一個(gè)新實(shí)例需要使用
new
關(guān)鍵字
var jeremy = new Person;
- 可以創(chuàng)建自己的對象 —— 用戶定義對象;JS 提供預(yù)定義好的對象 —— 內(nèi)建對象
-
Array
等就是 JS 的內(nèi)建對象 - 由 Web 瀏覽器提供的預(yù)定義對象被成為宿主對象。主要包括
Form
、Image
和Element
??梢酝ㄟ^這些對象獲得關(guān)于某給定網(wǎng)頁上的表單、圖像和各種元素信息。 - 還有一種對象可以獲得關(guān)于給定網(wǎng)頁上的任何一個(gè)元素的信息 ——
document
對象
-
3. DOM
DOM: Document Object Model 文檔對象模型
當(dāng)瀏覽器加載了一個(gè)網(wǎng)頁后,DOM 根據(jù)網(wǎng)頁文檔創(chuàng)建了一文檔對象。
對象是一種獨(dú)立的數(shù)據(jù)集合,與對象相關(guān)聯(lián)的變量稱為對象的屬性,通過對象調(diào)用的函數(shù)成為對象的方法。在 JS 中對象可以分為三種類型:
- 用戶定義對象 user-defined object:由程序員自行創(chuàng)建的對象
- 內(nèi)建對象 native object:內(nèi)建在 JS 語言里的對象,如 Array、Math 和 Date 等
- 宿主對象 host object:由瀏覽器提供的對象
在宿主對象中,window
對象是最基礎(chǔ)的對象,其對應(yīng)著瀏覽器窗口本身,這個(gè)對象的屬性和方法統(tǒng)稱為 BOM (瀏覽器對象模型)。相對于 BOM, DOM 主要用來對網(wǎng)頁的內(nèi)容進(jìn)行處理,而實(shí)現(xiàn)這一目標(biāo)的載體就是 document
對象
DOM 代表著被加載到瀏覽器窗口里的當(dāng)前網(wǎng)頁。DOM 把一份文檔表示為一棵樹。
節(jié)點(diǎn)
文檔是由節(jié)點(diǎn)構(gòu)成的集合,此時(shí)的節(jié)點(diǎn)代表文檔樹上的樹枝和樹葉。有的 DOM 節(jié)點(diǎn)還包含其他類型的節(jié)點(diǎn)。
-
元素節(jié)點(diǎn)
DOM 的原子即為 元素節(jié)點(diǎn) (element node)。這些元素在文檔中的布局形成了文檔的結(jié)構(gòu)。各種標(biāo)簽提供了元素的名字。元素可以包含其他元素 —— 唯一不會(huì)被其他元素包圍的元素是 <html> 元素,它是整個(gè)節(jié)點(diǎn)的根元素
-
文本節(jié)點(diǎn)
在 XHTML 中,文本節(jié)點(diǎn)總是被包含在元素節(jié)點(diǎn)的內(nèi)部,但并非所有的元素節(jié)點(diǎn)都包含由文本節(jié)點(diǎn)。
-
屬性節(jié)點(diǎn)
屬性是對元素的具體描述,屬性總是被放在起始標(biāo)簽里,所以屬性節(jié)點(diǎn)總是被包含在元素節(jié)點(diǎn)中。并非所有的元素都包含由屬性,但所有的屬性都被包含在元素中。
-
CSS
CSS 并不屬于 DOM,CSS 是告訴瀏覽器應(yīng)該如何顯示一份文檔的內(nèi)容。類似 DOM,CSS 也把文檔的內(nèi)容視為一顆節(jié)點(diǎn)樹。節(jié)點(diǎn)樹上的各元素繼承其父元素的樣式屬性。繼承是 CSS 的一項(xiàng)強(qiáng)大的功能,如當(dāng)為 body 元素定義了一些顏色或字體,包含在 body 元素里的所有元素都將自動(dòng)獲得 —— 也就是繼承這些樣式。
為了把一個(gè)或幾個(gè)元素與其他元素區(qū)別開來,經(jīng)常需要使用 class 屬性或 id 屬性
- class 屬性
所有的元素都由 class 屬性,不同的元素可以有相同的 class 屬性值。
- id 屬性
id 屬性的用途是給網(wǎng)頁里的某個(gè)元素加上一個(gè)獨(dú)一無二的標(biāo)識(shí)符。每個(gè)元素只能由一個(gè) id 屬性值,不同的元素必須由不同的 id 屬性值。id 屬性用于連接文檔中的某個(gè)元素和 CSS 樣式表里的某個(gè)樣式。
getElementById() 方法
這個(gè)方法將返回一個(gè)與給定 id 屬性值的元素節(jié)點(diǎn)相對應(yīng)的對象。這個(gè)方法是與 document 相關(guān)聯(lián)的函數(shù)。使用時(shí)函數(shù)名后邊必須根由一對圓括號(hào),包含著函數(shù)的參數(shù) —— 即所要獲得的那個(gè)元素的 id 值,這個(gè) id 值必須放在單引號(hào)或雙引號(hào)中。
document.getElementById('idValue')
這個(gè)調(diào)用會(huì)返回對應(yīng) id 值的那個(gè) document 對象。由于 id 值是獨(dú)一無二的,所以返回的對象也是唯一的。
文檔中的每一個(gè)元素都對應(yīng)著一個(gè)對象。利用 DOM 提供的方法,可以把這些元素相對應(yīng)的任何一個(gè)對象篩選出來。
一般來說,不需要對文檔中的每一個(gè)元素都定義一個(gè) id 值,除了使用 id 值外,可以使用其他 DOM 方法來篩選對象。
getElementsByTagName() 方法
getElementByTagName() 方法將返回一個(gè)對象數(shù)組,每個(gè)對象分別對應(yīng)文檔中有給定標(biāo)簽的一個(gè)元素。類似 getElementById(),這個(gè)方法也只有一個(gè)參數(shù) —— 標(biāo)簽的名字。
document.getElementByTagName(tagValue)
與 getElementById() 十分類似,但是 getElementByTagName() 方法返回的是一個(gè)對象數(shù)組。
getElementByTagName() 方法還允許我們把一個(gè)通佩符當(dāng)作它的參數(shù),這樣文檔中的所有元素都會(huì)被返回。
getAttribute() 方法
當(dāng)我們定位到特定元素節(jié)點(diǎn)后,可以使用 getAttribute() 方法把它的屬性值查詢出來。這個(gè)方法的參數(shù)也是一個(gè) —— 需要查詢的屬性的名字。
object.Attribute(attribute)
getAttribute() 方法不能通過 document 對象調(diào)用,必須通過一個(gè)元素節(jié)點(diǎn)對象來調(diào)用。當(dāng)需要查詢的屬性不存時(shí)則返回 null。
setAttribute() 方法
setAttribute() 方法用于對屬性節(jié)點(diǎn)的值進(jìn)行修改。類似于 getAttribute() 方法,必須通過元素節(jié)點(diǎn)對象調(diào)用的函數(shù),但 setAttribute() 方法需要傳遞兩個(gè)參數(shù):
object.setAttribute(attribute, value)
即便要更改的屬性并不存在,setAttribute() 也可以首先將屬性創(chuàng)建出來,然后對值進(jìn)行設(shè)置。如果屬性存在,則直接將原有的值覆蓋。
- 通過 setAttribute() 方法對文檔做出的修改,將使得文檔在瀏覽器窗口里的顯示效果或行為動(dòng)作發(fā)出相應(yīng)的變化,但查看源代碼會(huì)發(fā)現(xiàn)原來的屬性值并沒有發(fā)生變化。這表明了 DOM 的一個(gè)重要特性:先加載文檔的靜態(tài)內(nèi)容、再以動(dòng)態(tài)的方式對它們進(jìn)行刷新,動(dòng)態(tài)刷新不影響文檔的靜態(tài)內(nèi)容。—— 因此 DOM 對頁面內(nèi)容的刷新不需要用戶執(zhí)行刷新操作。
4. 案例研究: JS 美術(shù)館
4.3 JS 函數(shù)的調(diào)用
-
事件處理函數(shù)
事件處理函數(shù)的作用是,在預(yù)定事件發(fā)生時(shí)讓預(yù)先安排好的 JS 代碼開始執(zhí)行,用術(shù)語來說就是 “觸發(fā)一個(gè)動(dòng)作”。例如,如果想在鼠標(biāo)指針懸停在某個(gè)元素上時(shí)觸發(fā)一個(gè)動(dòng)作,就需要使用
onmouseover
事件處理函數(shù);如果想在鼠標(biāo)指針離開某個(gè)元素時(shí)觸發(fā)一個(gè)動(dòng)作,就需要使用onmouseout
事件處理函數(shù)。在通過
onclick
事件處理函數(shù)去觸發(fā)的動(dòng)作時(shí)調(diào)用showPick()
函數(shù),而要想調(diào)用這個(gè)函數(shù),就必須向它傳遞一個(gè)參數(shù):一個(gè)帶有href
屬性的元素節(jié)點(diǎn)。在圖片庫的案例中,當(dāng)把onclick
事件處理函數(shù)嵌入到一些鏈接中時(shí),需要把鏈接本身用作showPic()
函數(shù)的參數(shù),因此可以使用 JS 語言中的this
關(guān)鍵字:表示當(dāng)前所在的對象。使用事件處理函數(shù)調(diào)用 JS 代碼的語法如下:
event = "JavaScript statement(s);"
JS 代碼是包含在一對引號(hào)之間的,且可以把任意數(shù)量的 JS 語句放在這對引號(hào)之間,只要把各條語句用分號(hào)隔開即可。
在給某個(gè)元素添加了事件處理函數(shù)后,一旦發(fā)生預(yù)定的事件,相應(yīng)的 JS 代碼就會(huì)得到執(zhí)行;那些 JS 代碼可以返回一個(gè)結(jié)果,而這個(gè)結(jié)果將被傳遞回那個(gè)事件處理函數(shù)。比如可以給某個(gè)鏈接添加一個(gè)
onclick
事件處理函數(shù),并讓這個(gè)處理函數(shù)所觸發(fā)的 JS 代碼返回布爾值true
或false
。當(dāng)鏈接被點(diǎn)擊時(shí),如果 JS 返回的結(jié)果為true
,onclick
事件處理函數(shù)就會(huì)認(rèn)為“這個(gè)鏈接被點(diǎn)擊了”;反之,會(huì)認(rèn)為“這個(gè)鏈接沒有被點(diǎn)擊”。
4.4 對 JS 函數(shù)進(jìn)行功能擴(kuò)展
- childNodes 屬性
childNodes 將文檔的節(jié)點(diǎn)樹中任何一個(gè)元素的所有子元素檢索出來,childNodes 屬性將返回一個(gè)數(shù)組,這個(gè)數(shù)組包含給定元素節(jié)點(diǎn)的全體子元素:
element.childNodes
使用 childNodes 屬性獲取文檔中的 body 元素的全體子元素:
var body_element = document.getElementsByTagName("body")[0];
body_element.childNodes;
在 JS DOM 中,body 元素還有一個(gè)更簡單的專用記號(hào):document.body
- nodeType 屬性
由 childNode 屬性返回的數(shù)組包含所有類型的節(jié)點(diǎn) —— 除了所有的元素節(jié)點(diǎn),所有的屬性節(jié)點(diǎn)和文本節(jié)點(diǎn)也包含在其中。文檔樹的節(jié)點(diǎn)類型并非只有元素節(jié)點(diǎn)一種,在文檔中幾乎所有的東西都是一個(gè)節(jié)點(diǎn),連空格和換行符都會(huì)被解釋為節(jié)點(diǎn)。這些也都會(huì)被包含在 childNode 屬性返回的數(shù)組當(dāng)中。
因此需要利用 nodeType 屬性來區(qū)分文檔中的各個(gè)節(jié)點(diǎn)。nodeType 屬性返回一個(gè)數(shù)字來表示節(jié)點(diǎn)的類型,其中經(jīng)常用到的由三種:
- 1:元素節(jié)點(diǎn)
- 2:屬性節(jié)點(diǎn)
- 3:文本節(jié)點(diǎn)
使用 nodeType 的語法如下:
`node.nodeType`
- firstChild 和 lastChild 屬性
firstChild 和 lastChild 分別代表 childNodes[ ] 數(shù)組的第一個(gè)和最后一個(gè)元素。
`node.firstChild` <=> `node.childNodes[0]`
`node.lastChild` <=> `node.childNodes[node.childNodes.lenth-1]`
- nodeValue 屬性
nodeValue 屬性可以檢索和設(shè)置節(jié)點(diǎn)的值:
`node.nodeValue`
如果我們直接 nodeValue 屬性檢索一個(gè) <p> 對象的值時(shí),得到的并不是包含在這個(gè)元素中的文本,而是返回一個(gè) null 值。包含在 <p> 元素里的文本是另一種節(jié)點(diǎn),它在 DOM 里是 <p> 元素的第一個(gè)子節(jié)點(diǎn)。因此要想得到 <p> 元素的文本內(nèi)容,就必須檢索它的第一個(gè)子節(jié)點(diǎn)的 nodeValue 屬性值。
nodeValue 屬性不僅可以用來檢索某個(gè)節(jié)點(diǎn)的值,還可以用它來設(shè)置某個(gè)節(jié)點(diǎn)的值。將需要更改的內(nèi)容直接賦值給 nodeValue 屬性即可改變元素的 nodeValue 屬性
`element.firstChild.nodeValue` = text