前言
歸根結(jié)底,代碼都是思想和概念的體現(xiàn)搏熄。沒(méi)人能把一種程序設(shè)計(jì)語(yǔ)言的所有語(yǔ)法和關(guān)鍵字都記住,可以查閱參考書來(lái)解決暇赤。平穩(wěn)退化心例、漸進(jìn)增強(qiáng)、以用戶為中心的設(shè)計(jì)對(duì)任何前端Web開(kāi)發(fā)工作都非常重要鞋囊。
第1章 JavaScript簡(jiǎn)史
1 JavaScript的起源
Netscape公司和Sun公司合作開(kāi)發(fā)止后。第一個(gè)版本出現(xiàn)在1995年推出的Netscape Navigator2瀏覽器中。IE也以JScript為名發(fā)布了一個(gè)版本溜腐,面對(duì)IE的競(jìng)爭(zhēng)译株,Netscape和Sun聯(lián)合ECMA對(duì)JavaScript進(jìn)行了標(biāo)準(zhǔn)化——ECMAScript語(yǔ)言,就是現(xiàn)在談?wù)摰腏avaScript(以下均簡(jiǎn)稱JS)挺益。與Sun公司開(kāi)發(fā)的Java程序語(yǔ)言沒(méi)有任何關(guān)系歉糜。
2 DOM
DOM是一套對(duì)文檔內(nèi)容進(jìn)行抽象和概念化的方法。JS的早期版本向程序員提供了查詢和操控web文檔某些實(shí)際內(nèi)容的手段望众,主要是圖像和表單匪补,因?yàn)镴S預(yù)先定義了images和forms等術(shù)語(yǔ),通常把這種試驗(yàn)性質(zhì)的初級(jí)DOM成為0級(jí)DOM烂翰。
3 瀏覽器戰(zhàn)爭(zhēng)
Netscape Navigator 4發(fā)布于1997年6月夯缺,IE4發(fā)布于同年10月,兩者都大幅擴(kuò)展了DOM(但彼此不兼容)甘耿,使JS功能大大增加踊兜,出現(xiàn)一個(gè)新名詞:DHTML,即動(dòng)態(tài)HTML棵里,是描述HTML润文、CSS姐呐、JS技術(shù)組合的術(shù)語(yǔ)。
4 制定標(biāo)準(zhǔn)
瀏覽器制造商們攜手W3C于1998年制定完成了新的標(biāo)準(zhǔn)典蝌,即第1級(jí)DOM曙砂。標(biāo)準(zhǔn)化的DOM有遠(yuǎn)大的抱負(fù)载绿。
- 瀏覽器以外的考慮眷蜈。DOM是一種API(應(yīng)用編程接口)噪舀,API是一組已經(jīng)得到有關(guān)各方共同認(rèn)可的基本約定颂龙,如國(guó)際時(shí)區(qū)苛萎、化學(xué)元素周期表等亏狰。W3C對(duì)DOM的定義是:一個(gè)與系統(tǒng)平臺(tái)和編程語(yǔ)言無(wú)關(guān)的接口放刨,程序和腳本可以通過(guò)這個(gè)接口動(dòng)態(tài)地訪問(wèn)和修改文檔的內(nèi)容贡羔、結(jié)構(gòu)和樣式葵袭。
- 瀏覽器戰(zhàn)爭(zhēng)的結(jié)局涵妥。市場(chǎng)份額大戰(zhàn)中,微軟戰(zhàn)勝了Netscape坡锡。下一代瀏覽器產(chǎn)品對(duì)Web標(biāo)準(zhǔn)的支持得到了極大的改善蓬网。
- 嶄新的起點(diǎn)。如今鹉勒,safari(WebKit)帆锋、Chrome(WebKit)、Firefox(Gecko)禽额、IE(Trident)和一些智能手機(jī)都對(duì)DOM有良好的支持锯厢。
第2章 JS語(yǔ)法
1 準(zhǔn)備工作
編寫JS腳本:文本編輯器+腳本,必須通過(guò)HTML/XHTML文檔執(zhí)行脯倒。
兩種方式:
- 將JS代碼放到文檔<head>標(biāo)簽中的<script>標(biāo)簽之間
- 把JS代碼存為一個(gè)擴(kuò)展名為.js的獨(dú)立文件实辑,在<head>部分放入<script>標(biāo)簽,將其src屬性指向該文件
- 最好的做法是把<script>標(biāo)簽放在HTML文檔的最后盔憨,</body>之前徙菠,這樣能使瀏覽器更快地加載頁(yè)面
程序設(shè)計(jì)語(yǔ)言分為解釋型和編譯型兩大類。Java或C++等語(yǔ)言需要一個(gè)編譯器郁岩,能把源代碼翻譯為直接在計(jì)算機(jī)上執(zhí)行的文件婿奔。解釋型語(yǔ)言不需要編譯器,僅需要解釋器问慎。對(duì)于JS解釋器萍摊,瀏覽器負(fù)責(zé)完成有關(guān)的解釋和執(zhí)行工作。
2 語(yǔ)法
(1)語(yǔ)句如叼。建議在每條語(yǔ)句后面加分號(hào)冰木,這是一種良好的編程習(xí)慣。
(2)注釋。有效幫助了解代碼流程踊沸,多種注釋方法歇终。建議用“//”來(lái)注釋單行,用“/*”注釋多行逼龟。
(3)變量评凝。將值存入變量的操作,叫賦值腺律。提前聲明變量是一種良好的編程習(xí)慣奕短,雖然JS沒(méi)有強(qiáng)制要求。最有效率的方法是聲明和賦值一次完成:
var mood="happy",age=26;
相當(dāng)于:
var mood,age;
mood="happy";
age=33;
JS中變量和其他語(yǔ)法元素的名字都區(qū)分字母大小寫匀钧,不允許變量名中包括空格或標(biāo)點(diǎn)符號(hào)(美元符號(hào)除外)翎碑,允許包括字母、數(shù)字之斯、美元符號(hào)和下劃線日杈,第一個(gè)字符不允許是數(shù)字。如變量名my mood無(wú)效佑刷,可用my_mood达椰,或myMood,這種駝峰格式是函數(shù)名项乒、方法名和對(duì)象屬性名命名的首選格式。
(4)數(shù)據(jù)類型梁沧。上述代碼中檀何,變量mood的值是字符串,變量age的值是數(shù)字廷支,類型不同但聲明和賦值語(yǔ)法完全相同频鉴。有些其他語(yǔ)言還要求聲明數(shù)據(jù)類型,稱為強(qiáng)類型語(yǔ)言恋拍,而JS屬于弱類型語(yǔ)言垛孔。JS中的幾種數(shù)據(jù)類型:
- 字符串。包括(但不限于)字母施敢、數(shù)字周荐、標(biāo)點(diǎn)符號(hào)和空格,必須包在引號(hào)里僵娃,單雙均可概作,但最好在整個(gè)文本里保持一致。如果字符串里本身含引號(hào)造成一定干擾默怨,可使用反斜線\進(jìn)行轉(zhuǎn)義讯榕,如‘don't ask'。
- 數(shù)值。允許任意位小數(shù)愚屁,稱為浮點(diǎn)數(shù)济竹,也可以是負(fù)數(shù)。
- 布爾值霎槐。布爾數(shù)據(jù)只有兩個(gè)可選值:true 或者false送浊。布爾值不是字符串,不要用引號(hào)括起來(lái)栽燕,false和“false”是兩碼事罕袋。
(5)數(shù)組。字符串碍岔、數(shù)值和布爾值都是標(biāo)量(scalar)浴讯,它只能有一個(gè)值。而數(shù)組是指用一個(gè)變量表示一個(gè)值的集合蔼啦,集合中的每個(gè)值都是這個(gè)數(shù)組的一個(gè)元素榆纽。
JS數(shù)組可以用關(guān)鍵字Array聲明,聲明的同時(shí)還可以指定初始元素個(gè)數(shù)捏肢,即數(shù)組長(zhǎng)度奈籽。
var beatles=Array(4);或 var beatles=Array()
向數(shù)組添加元素的操作稱為填充(populating)。填充時(shí)鸵赫,需要給出新元素的值及其在數(shù)組中的存放位置衣屏,即元素的下標(biāo)(index),下標(biāo)必須用方括號(hào)括起來(lái):
array[index]=element;
如,var beatles=Array(4);
beatles[0]="John";(JS規(guī)定0作為第一個(gè)下標(biāo))
beatles[1]="Paul";
beatles[2]="George";
beatles[3]="Ringo";
簡(jiǎn)便寫法:
var beatles=Array("John","Paul","George","Ringo");
或者:
var beatles=["John","Paul","George","Ringo"];
數(shù)組元素可以是字符辩棒、數(shù)字狼忱、布爾值:
var lennon=["John",1940,false];
還可以是變量:
var name="John";
var beatles[0]=name;
還可以是另一個(gè)數(shù)組的元素:
var names=["Ringo","John","George","Paul"];
beatles[1]=names[3];
還可以包含其他的數(shù)組:
var lennon=["John",1940,false];
var beatles=[];
beatles[0]lennon;
則beatles[0][1]的值是1940.
但如果要記住每個(gè)下標(biāo)數(shù)字的話,編程工作將十分麻煩一睁,幸好還有其他方法可以填充數(shù)組:關(guān)聯(lián)數(shù)組钻弄;將數(shù)組保存為對(duì)象。
關(guān)聯(lián)數(shù)組:
如果在填充數(shù)組時(shí)只給出了元素的值者吁,這個(gè)數(shù)組將是一個(gè)傳統(tǒng)數(shù)組窘俺,它的各個(gè)元素的下標(biāo)將被自動(dòng)創(chuàng)建和刷新。在為新元素給出下標(biāo)時(shí)复凳,不必局限于使用整數(shù)數(shù)字瘤泪,還可以用字符串:
var lennon=Array();
lennon["name"]="John";
lennon["year"]=1940;
lennon["living"]=false;
這樣的數(shù)組叫關(guān)聯(lián)數(shù)組,代碼更具有可讀性育八,但這種用法不是一個(gè)好習(xí)慣均芽,不推薦使用。本質(zhì)上单鹿,在創(chuàng)建關(guān)聯(lián)數(shù)組時(shí)掀宋,創(chuàng)建的是Array對(duì)象的屬性。在JS中所有變量實(shí)際上都是某種類型的對(duì)象。理想情況下劲妙,不應(yīng)該修改Array對(duì)象的屬性湃鹊,而應(yīng)該使用通用的對(duì)象(Object)。
(6)對(duì)象
與數(shù)組類似镣奋,對(duì)象也是使用一個(gè)名字表示一組值币呵。對(duì)象的每個(gè)值都是對(duì)象的一個(gè)屬性,前一節(jié)的lennon數(shù)組也可以創(chuàng)建成下面這個(gè)對(duì)象:
var lennon=Object();
lennon.name="John";
lennon.year=1940;
lennon.living=false;
它不使用方括號(hào)和下標(biāo)來(lái)獲取元素侨颈,而是像任何JS對(duì)象一樣余赢,使用點(diǎn)號(hào)來(lái)獲取屬性。創(chuàng)建對(duì)象還有一種更簡(jiǎn)潔的語(yǔ)法哈垢,即花括號(hào)語(yǔ)法:
var lennon={name:"John",year:1940,living:false};
用對(duì)象來(lái)代替?zhèn)鹘y(tǒng)數(shù)組的做法意味著可以通過(guò)元素的名字而不是下標(biāo)數(shù)字來(lái)引用它們妻柒,這大大提高了腳本的可讀性。
3 操作
進(jìn)行計(jì)算和處理數(shù)據(jù)耘分,即操作(operation)举塔。
算術(shù)操作符
變量可以包含操作:var total=(1+4)*5;
還可以對(duì)變量進(jìn)行操作:var temp_fahrenheit=95;var temp_celsius=(temp_fahrenheit-32)/1.8;
加號(hào)(+)是一個(gè)比較特殊的操作符,既可用于數(shù)值求泰,也可用于字符串:
var message="I am feeling"+"happy";
這種把多個(gè)字符串首尾相連的操作叫拼接(concatenation)央渣。
拼接可通過(guò)變量完成:
var mood="happy";
var message="I am feeling"+mood;
還可以把數(shù)值和字符串拼接
var year=2005;
var message="The year is"+year;
把字符串和數(shù)字拼接在一起,結(jié)果是一個(gè)更長(zhǎng)的字符串渴频,兩個(gè)數(shù)值拼接在一起芽丹,結(jié)果是兩個(gè)數(shù)值的算術(shù)和。
快捷操作符:
++相當(dāng)于+1卜朗;
+=則是一次完成“拼接和賦值”:
var year=2010;
var message="The year is";
message+=year;
結(jié)果是變量message的值為“The year is 2005”志衍。
4 條件語(yǔ)句
最常見(jiàn)的條件語(yǔ)句是if語(yǔ)句,基本語(yǔ)法:if (condition) {statements;},其中condition的求值結(jié)果永遠(yuǎn)是一個(gè)布爾值聊替。if語(yǔ)句可以有一個(gè)else子句,其語(yǔ)句會(huì)在給定condition為false時(shí)執(zhí)行培廓。
(1)比較操作符惹悄。
- 等于。注意(=)是賦值,(==)才是等于肩钠。(==)不表示嚴(yán)格相等泣港,而(===)表示全等操作符,不僅比較值价匠,還會(huì)比較變量類型当纱。
var my_mood="happy";
var your_mood="sad";
if (my_mood==your_mood){
alert("we both feel the same");
}
- 不等于。(!=)踩窖,嚴(yán)格不相等需使用(!==)
if (my_mood != your_mood){
alert("We are feeling different moods.");
}
(2)邏輯操作符坡氯。把條件語(yǔ)句里的操作組合在一起,需使用邏輯操作符。
- 邏輯與&&箫柳。兩個(gè)操作數(shù)都true才是true手形。
if (num>=5 && num<=10){
alert("The number is in the right range.");
}
- 邏輯或||。一個(gè)true就是true悯恍。
- 邏輯非库糠!。
if (!(5>10||5<1)){
alert("The number is in the right range.");
}
5 循環(huán)語(yǔ)句
if 語(yǔ)句的不足是無(wú)法完成重復(fù)性操作涮毫,如需多次執(zhí)行同一個(gè)代碼塊瞬欧,必須使用循環(huán)語(yǔ)句,其工作原理是只要給定條件仍能滿足罢防,包含在循環(huán)語(yǔ)句里的代碼就會(huì)重復(fù)執(zhí)行艘虎,一旦給定條件的求值結(jié)果不再是true,循環(huán)終止。
(1)while 循環(huán)篙梢。與if語(yǔ)句的語(yǔ)法幾乎完全一樣顷帖,唯一的區(qū)別是只要給定條件求值結(jié)果是true,花括號(hào)里的代碼就將反復(fù)執(zhí)行。
var count=1;
while(count<11){
alert(count);
count++;
}
對(duì)循環(huán)控制條件的求值發(fā)生在每次循環(huán)開(kāi)始之前渤滞,如果控制條件首次求值結(jié)果是false贬墩,那么花括號(hào)里的代碼將一個(gè)也不會(huì)被執(zhí)行。在某些場(chǎng)合妄呕,為保證代碼至少執(zhí)行一次陶舞,用到do...while循環(huán),其對(duì)循環(huán)控制條件的求值發(fā)生在每次循環(huán)結(jié)束之后绪励。
var count=1;
do{
alert(count);
count++;
}while(count<11);
(2)for循環(huán)肿孵。是while循環(huán)的一種變體。
for(initial condition;test condition;alter condition){
statements;
} 用for循環(huán)來(lái)重復(fù)執(zhí)行代碼的好處是循環(huán)控制結(jié)構(gòu)更加清晰疏魏。上例:
for (var count=1; count<11;count++){
alert(count);
}
for循環(huán)最常見(jiàn)的用途之一是對(duì)某個(gè)數(shù)組里的全體元素進(jìn)行遍歷處理:
var beatles=Array("John","Paul","George","Ringo");
for(var count=0;count<beatles.length;count++){
alert(beatles[count]);
}
6 函數(shù)
每當(dāng)需要反復(fù)做一件事時(shí)停做,都可以利用函數(shù)來(lái)避免重復(fù)鍵入大量相同內(nèi)容,不過(guò)函數(shù)的真正威力體現(xiàn)在大莫,你可以把不同數(shù)據(jù)傳遞給它們蛉腌,完成預(yù)定操作。把傳遞給函數(shù)的數(shù)據(jù)稱為參數(shù)(argument)只厘。JS提供了很多內(nèi)建函數(shù)烙丛,如前面的alert。
定義一個(gè)函數(shù)的語(yǔ)法:
function name(arguments){
statements;
}
如傳遞兩個(gè)參數(shù)的函數(shù):
function multiply(num1,num2){
var total=num1*num2;
alert(total);
}
定義了這個(gè)函數(shù)的腳本羔味,可從任意位置調(diào)用
multiply(10,2);
函數(shù)不僅能夠以參數(shù)的形式接收數(shù)據(jù)河咽,還能夠返回?cái)?shù)據(jù),需用到return語(yǔ)句赋元。
函數(shù)的真正價(jià)值體現(xiàn)在忘蟹,可以把它們當(dāng)做一種數(shù)據(jù)類型來(lái)使用飒房,變量用下劃線,函數(shù)用駝峰命名法寒瓦,可予以區(qū)分情屹。
變量的作用域(scope)
- 全局變量global variable,可以在腳本中的任何位置被引用杂腰。
- 局部變量local variable垃你,只存在于聲明它的函數(shù)內(nèi)部。
如果在某個(gè)函數(shù)中使用了var喂很,那個(gè)變量就是局部變量惜颇,否則視為全局變量,如果腳本里已經(jīng)存在一個(gè)與之同名的全局變量少辣,這個(gè)函數(shù)就會(huì)改變那個(gè)全局變量的值凌摄。所以定義一個(gè)函數(shù)時(shí),一定要把它內(nèi)部的變量全都明確地聲明為局部變量漓帅,避免隱患锨亏。
7 對(duì)象
包含在對(duì)象里的數(shù)據(jù)可以通過(guò)兩種形式訪問(wèn)——屬性property和方法method。屬性是隸屬于某個(gè)特定對(duì)象的變量忙干,方法是只有某個(gè)特定對(duì)象才能調(diào)用的函數(shù)器予。
Person.mood
Person.age
Person.walk()
使用new關(guān)鍵字,為對(duì)象創(chuàng)建實(shí)例instance:
var jeremy=new Person捐迫;
就可以用Person對(duì)象的屬性來(lái)檢索關(guān)于jeremy的信息了:
jeremy.age
jeremy.mood
(1)內(nèi)建對(duì)象乾翔。
數(shù)組就是一種,還有Meth施戴、Date等反浓。
(2)宿主對(duì)象。
這些對(duì)象不是由JS語(yǔ)言本身而是由它的運(yùn)行環(huán)境提供的赞哗。具體到Web應(yīng)用雷则,這個(gè)環(huán)境就是瀏覽器,由瀏覽器提供的預(yù)定義對(duì)象被稱為宿主對(duì)象肪笋,如Form月劈、Image等。
第3章 DOM
1 文檔:DOM中的D
當(dāng)創(chuàng)建了一個(gè)網(wǎng)頁(yè)并把它加載到Web瀏覽器中時(shí)涂乌,你編寫的網(wǎng)頁(yè)文檔就轉(zhuǎn)換為一個(gè)文檔對(duì)象了。
2 對(duì)象:DOM中的O
JS對(duì)象分三種類型:用戶自定義對(duì)象英岭、內(nèi)建對(duì)象湾盒、宿主對(duì)象。
3 模型:DOM中的M
就像一個(gè)模型火車代表著一列真正的火車诅妹,DOM代表著加載到瀏覽器窗口的當(dāng)前網(wǎng)頁(yè)罚勾。DOM把文檔表示為一棵家譜樹(shù)毅人,稱為“節(jié)點(diǎn)樹(shù)”更準(zhǔn)確。
4 節(jié)點(diǎn)
節(jié)點(diǎn)node表示網(wǎng)絡(luò)中的一個(gè)連接點(diǎn)尖殃,一個(gè)網(wǎng)絡(luò)就是由一些節(jié)點(diǎn)構(gòu)成的集合丈莺。
DOM里有三種不同類型的節(jié)點(diǎn):元素節(jié)點(diǎn)、文本節(jié)點(diǎn)送丰、屬性節(jié)點(diǎn)。
獲取元素
- getElementById.這個(gè)方法將返回一個(gè)與有著給定id屬性值的元素節(jié)點(diǎn)對(duì)應(yīng)的對(duì)象。如document.getElementById("purchases")驱入。
- getElementsByTagName.這個(gè)方法將返回一個(gè)對(duì)象數(shù)組多矮,每個(gè)對(duì)象分別對(duì)應(yīng)著文檔里有著給定標(biāo)簽的一個(gè)元素。為了減少不必要的打字量并改善代碼可讀性登失,可把document.getElementsByTagName("")賦值給一個(gè)變量遏佣。
getElementsByTagName還允許把通配符作為參數(shù),如alert(document.getElementsByTagName("*").length);
還可以跟getElementById結(jié)合起來(lái)運(yùn)用揽浙。 - getElementsByClassName.
5 獲取和設(shè)置屬性
(1)getAttribute.是只有一個(gè)參數(shù)的函數(shù)状婶,但它不屬于document對(duì)象,所以不能通過(guò)document對(duì)象調(diào)用馅巷,只能通過(guò)元素節(jié)點(diǎn)對(duì)象調(diào)用膛虫。
(2)setAttribute.它允許我們隊(duì)屬性節(jié)點(diǎn)值做出修改,也是只能用于元素節(jié)點(diǎn)令杈。
object.setAttribute(attribute,value)
var shopping = document.getElementById("purchases");
alert(shopping.getAttribute("title"));
shopping.setAttribute("title","a list of goods");
alert(shopping.getAttribute("title"));
第一個(gè)alert顯示null走敌,第二個(gè)alert顯示a list of goods。這表明setAttribute實(shí)際上完成了兩項(xiàng)操作:先創(chuàng)建屬性逗噩,然后設(shè)置它的值掉丽。
一個(gè)細(xì)節(jié):通過(guò)setAttribute對(duì)文檔做出修改后,查看源代碼時(shí)看到的仍是改變前的屬性值异雁。這種現(xiàn)象源自DOM的工作模式:先加載文檔的靜態(tài)內(nèi)容捶障,再動(dòng)態(tài)刷新,動(dòng)態(tài)刷新不影響文檔的靜態(tài)內(nèi)容纲刀。
第4章 案例研究:JS圖片庫(kù)
1 標(biāo)記
第一項(xiàng)工作是為這些圖片創(chuàng)建一個(gè)鏈接清單项炼。如果圖片有排序,用<ol>示绊,無(wú)排序锭部,用 <ul>。增加一個(gè)占位符圖片為圖片預(yù)留一個(gè)瀏覽區(qū)域面褐。
<ul>
<li>
<a href="images/1.jpg" onclick="showPic(this);return false;" title="gray">gray</a>
</li>
<li>
<a href="images/2.jpg" onclick="showPic(this);return false;" title="ziont1">ziont</a>
</li>
</ul>
<img id="placeholder" src="" alt="my image gallery">
2 JS
function showPic(whichpic){
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
placeholder.setAttribute("src",source);
}
函數(shù)取名為showPic,其參數(shù)取名為whichpic.通過(guò)getAttribute獲取whichpic對(duì)象的href屬性,通過(guò)getElementById獲取占位符圖片,通過(guò)setAttribute更改占位符圖片的src屬性拌禾。
3 應(yīng)用這個(gè)函數(shù)
需要在html文件中添加事件處理函數(shù)(event handler).
事件處理函數(shù)的作用是,在特定事件發(fā)生時(shí)調(diào)用特定的JS代碼展哭。如onmouseover湃窍、onmouseout闻蛀、onclick函數(shù)。
當(dāng)把onclick函數(shù)嵌入到一個(gè)鏈接中時(shí)您市,需要把這個(gè)鏈接本身用作showPic函數(shù)的參數(shù)觉痛,可使用this關(guān)鍵字:onclick="showPic(this);"
但是,點(diǎn)擊這個(gè)鏈接時(shí)茵休,不僅showPic函數(shù)被調(diào)用薪棒,鏈接被點(diǎn)擊的默認(rèn)行為也會(huì)被調(diào)用,如何阻止這個(gè)默認(rèn)行為被調(diào)用泽篮。事件處理函數(shù)的工作機(jī)制是盗尸,一旦事件發(fā)生,相應(yīng)的JS代碼就會(huì)被執(zhí)行帽撑。被調(diào)用的JS代碼可以返回給事件函數(shù)一個(gè)值泼各。如果讓返回的是一個(gè)布爾值,如該例中return false亏拉,則onclick就認(rèn)為“這個(gè)鏈接沒(méi)有被點(diǎn)擊”扣蜻。
4 擴(kuò)展這個(gè)函數(shù)
(1)childNodes屬性。
在一棵節(jié)點(diǎn)樹(shù)上及塘,childNodes屬性可以用來(lái)獲取任何一個(gè)元素的所有子元素莽使,它是一個(gè)包含這個(gè)元素全部子元素的數(shù)組:element.childNodes.
如需精確查出body元素一共有多少個(gè)子元素:
function countBodyChildren(){
var body_element = document.getElementsByTagName("body")[0];
alert(body_element.childNodes.length);
}
window.onload = countBodyChildren;
(2)nodeType屬性。
nodeType共有12種可取值笙僚,但其中僅有3種具有實(shí)用價(jià)值芳肌。
- 元素節(jié)點(diǎn)的nodeType屬性值是1
- 屬性節(jié)點(diǎn)的nodeType屬性值是2
- 文本節(jié)點(diǎn)的nodeType屬性值是3
(3)為標(biāo)記里增加一段描述。
首先肋层,為目標(biāo)文本安排顯示位置亿笤,設(shè)置id值。
<p id="description">Choose an picture.</p>
目的是圖片鏈接被點(diǎn)擊時(shí)栋猖,不僅把占位符圖片替換為那個(gè)href屬性指向的圖片净薛,還要把這段文本同時(shí)替換為那個(gè)圖片鏈接的title屬性值。
(4)用JS改變這段描述蒲拉。
修改showPic()函數(shù):
function showPic(whichpic){
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
placeholder.setAttribute("src",source);
var text = whichpic.getAttribute("title");
var description = document.getElementById("description");
}
(5)nodeValue屬性肃拜。
如果想改變一個(gè)文本節(jié)點(diǎn)的值,要使用DOM提供的nodeValue屬性雌团,它用來(lái)得到(和設(shè)置)一個(gè)節(jié)點(diǎn)的值燃领。注意:<p>元素本身的nodeValue屬性是一個(gè)空值,包含在<p>元素里的文本是另一種節(jié)點(diǎn)锦援,它是p元素的第一個(gè)子節(jié)點(diǎn)猛蔽。要修改p元素的文本值,需要獲取的是文本而不是p雨涛,因此下面兩條語(yǔ)句枢舶,第一條返回null,第二條才是文本值替久。
alert(description.nodeValue);
alert(description.childNodes[0].nodeValue);
(6)firstChild和lastChild屬性凉泄。
數(shù)組元素childNodes[0]有個(gè)更直觀易讀的同義詞:firstChild.與之對(duì)應(yīng)的是lastChild.
(7)利用nodeValue屬性刷新這段描述。
function showPic(whichpic){
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
placeholder.setAttribute("src",source);
var text = whichpic.getAttribute("title");
var description = document.getElementById("description");
description.firstChild.nodeValue = text;
}
第5章 最佳實(shí)踐
1 過(guò)去的錯(cuò)誤
(1)JS
易學(xué)易用的技術(shù)是一把雙刃劍蚯根,容易被廣泛應(yīng)用后众,但往往缺乏高水平的質(zhì)量控制。一些現(xiàn)成的JS函數(shù)里有很多問(wèn)題考慮不周全颅拦。一旦瀏覽器不支持或禁用了JS解釋功能蒂誉,那些質(zhì)量低劣的腳本就會(huì)導(dǎo)致用戶無(wú)法瀏覽相應(yīng)的網(wǎng)頁(yè)甚至整個(gè)網(wǎng)站。
(2)flash
(3)質(zhì)疑
網(wǎng)站對(duì)JS的濫用已經(jīng)持續(xù)了相當(dāng)長(zhǎng)的時(shí)間距帅。如果要使用JS右锨,就要確認(rèn):這么做會(huì)對(duì)用戶瀏覽體驗(yàn)產(chǎn)生什么影響?用戶瀏覽器不支持JS該怎么辦碌秸?
2 平穩(wěn)退化
如果正確地使用了JS腳本绍移,就可以讓訪問(wèn)者在他們?yōu)g覽器不支持JS的情況下仍能順利地瀏覽你的網(wǎng)站,這就是所謂的平穩(wěn)退化讥电,就是說(shuō)雖然某些功能無(wú)法使用蹂窖,但最基本的操作仍能順利完成。舉例:創(chuàng)建新的瀏覽器窗口 window.open(url,name,features)
(1)JS偽協(xié)議
“真”協(xié)議用來(lái)在因特網(wǎng)上的計(jì)算機(jī)之間傳輸數(shù)據(jù)包恩敌,如HTTP協(xié)議瞬测、FTP協(xié)議等,偽協(xié)議則是一種非標(biāo)準(zhǔn)化的協(xié)議纠炮,偽協(xié)議讓我們通過(guò)一個(gè)鏈接來(lái)調(diào)用JS函數(shù)月趟。
如調(diào)用popUp()函數(shù):
<a hret="javascript:popUp('http://www.example.com/');">Example</a>
這條語(yǔ)句在支持“javascript:”偽協(xié)議的瀏覽器中運(yùn)行正常,較老的瀏覽器會(huì)失敗抗碰,支持這種偽協(xié)議但禁用了JS功能的瀏覽器什么也不會(huì)做狮斗。總之在HTML文檔中通過(guò)“javascript:”偽協(xié)議調(diào)用JS代碼的做法非常不好弧蝇。
(2)內(nèi)嵌的事件處理函數(shù)
<a href="#" onclick="popUp('http://www.example.com/');
return false;">Example</a>
把href值設(shè)置為“#”只是為了創(chuàng)建一個(gè)空鏈接碳褒,實(shí)際工作全部由onclick屬性負(fù)責(zé)完成。這個(gè)方法同樣不能平穩(wěn)退化看疗。
(3)平穩(wěn)退化的重要性
一個(gè)重要的訪問(wèn)者:搜索機(jī)器人(searchbot)沙峻。目前只有極少數(shù)搜索機(jī)器人能理解JS代碼(?)两芳。如果你的JS網(wǎng)頁(yè)不能平穩(wěn)退化摔寨,它們?cè)谒阉饕嫔系呐琶涂赡艽笫軗p害。一個(gè)解決辦法怖辆,具體到popUp()函數(shù)是复,把href屬性設(shè)置為真實(shí)存在的URL地址:
<a
onclick="popUp('http://www.example.com');return false;">Example</a>
上述代碼可簡(jiǎn)化為
<a
onclick="popUp(this.href);return false;">Example</a>
3 向CSS學(xué)習(xí)
(1)結(jié)構(gòu)與樣式的分離
具備CSS支持的瀏覽器可以把網(wǎng)頁(yè)呈現(xiàn)得美輪美奐删顶,不支持或禁用了CSS功能的瀏覽器同樣可以把網(wǎng)頁(yè)的內(nèi)容按照正確的結(jié)構(gòu)顯示出來(lái)。
(2)漸進(jìn)增強(qiáng)
所謂“漸進(jìn)增強(qiáng)”就是用一些額外的信息層去包裹原始數(shù)據(jù)淑廊,按照漸進(jìn)增強(qiáng)原則創(chuàng)建出來(lái)的網(wǎng)頁(yè)幾乎都符合平穩(wěn)退化原則逗余。如果說(shuō)CSS是提供“表示”,則JS是提供“行為”季惩。把CSS代碼從HTML文檔里分離出來(lái)可以讓CSS工作得更好录粱,這同樣適用于JS行為層。
4 分離JS
<a class="popup">Example</a>
如何實(shí)現(xiàn)當(dāng)這個(gè)鏈接被點(diǎn)擊時(shí)画拾,它將調(diào)用popUp()函數(shù):JS語(yǔ)言不要求事件必須在HTML文檔里處理啥繁,可以在外部JS文件里把一個(gè)事件添加到HTML文檔中的某個(gè)元素上,可以利用class或id屬性來(lái)解決青抛。具體步驟:
(1)把文檔中所有鏈接全放入一個(gè)數(shù)組里
(2)遍歷數(shù)組
(3)如果某個(gè)鏈接的class屬性等于popup旗闽,就表示這個(gè)鏈接在被點(diǎn)擊時(shí)應(yīng)調(diào)用popUp()函數(shù)。
window.onload = prepareLinks;
function prepareLinks(){
var links = document.getElementsByTagName("a");
for (var i=0;i<links.length;i++){
if (links[i].getAttribute("class")=="popup"){
links[i].onclick=function(){
popUp(this.getAttribute("href"));
return false;
}
}
}
}
function popUp(winURL){
window.open(winURL,"popup",width=320,height=480");
}
以上代碼將調(diào)用popUp()函數(shù)的onclick事件添加到有關(guān)鏈接上蜜另,等于把這些操作從HTML文檔里分離出來(lái)宪睹,這就是“分離JavaScript”。另外蚕钦,為保證HTML文檔加載完再加載腳本亭病,可將代碼打包到preparelinks()函數(shù),并將其添加到windows對(duì)象的onload事件上嘶居。
5向后兼容
(1)對(duì)象檢測(cè)
檢測(cè)瀏覽器對(duì)JS的支持程度罪帖。只要把某個(gè)方法打包在一個(gè)if語(yǔ)句里,就可以根據(jù)這條if語(yǔ)句的條件表達(dá)式求值結(jié)果是true還是false來(lái)決定采取怎樣的行動(dòng)邮屁。這種檢測(cè)稱為對(duì)象檢測(cè)整袁。
if(method){
statements
}
但如此編寫出來(lái)的函數(shù)會(huì)增加一對(duì)花括號(hào),如果需要在函數(shù)里檢測(cè)多個(gè)DOM方法和/或?qū)傩允欠翊嬖谟恿撸@個(gè)函數(shù)最重要的語(yǔ)句就會(huì)深埋在一層又一層的花括號(hào)里坐昙,這樣的代碼往往很難閱讀和理解。把測(cè)試條件改為“如果你不理解這個(gè)方法芋忿,就離開(kāi)”則更簡(jiǎn)單炸客。如:
if(!getElementById || !getElementsByTagName)return false;
(2)瀏覽器嗅探技術(shù)
這是一種風(fēng)險(xiǎn)很大的技術(shù)。一是瀏覽器有時(shí)會(huì)撒謊戈钢,二是為適用于多種瀏覽器痹仙,嗅探腳本會(huì)越來(lái)越復(fù)雜,三是許多嗅探腳本在進(jìn)行此類測(cè)試時(shí)殉了,要求瀏覽器版本號(hào)必須得到精確匹配开仰,因此需要一直修改。這種技術(shù)正在被更簡(jiǎn)單更健壯的對(duì)象檢測(cè)技術(shù)所取代。
6 性能考慮
(1)盡量少訪問(wèn)DOM和盡量減少標(biāo)記众弓。在多個(gè)函數(shù)都會(huì)取得一組類似元素的情況下恩溅,可以考慮重構(gòu)代碼,把搜索結(jié)果保存在一個(gè)全局變量里谓娃,或者把一組元素直接以參數(shù)形式傳遞給函數(shù)暴匠。并且要盡量減少文檔中的標(biāo)記數(shù)量。
(2)合并和放置腳本傻粘。包含腳本的最佳方式就是使用外部文件。減少請(qǐng)求數(shù)量通常都是在性能優(yōu)化時(shí)首先要考慮的帮掉。腳本在標(biāo)記中的位置對(duì)頁(yè)面的初次加載時(shí)間也有很大影響弦悉。傳統(tǒng)上放在<head>里,但會(huì)導(dǎo)致瀏覽器無(wú)法并行加載其他文件蟆炊。一般來(lái)說(shuō)根據(jù)HTTP規(guī)范稽莉,瀏覽器每次從同一域名中最多只能同時(shí)下載兩個(gè)文件。把所有<script>標(biāo)簽都放到文檔的末尾涩搓,</body>標(biāo)記前污秆,可以讓頁(yè)面變得更快(?)
(3)壓縮腳本昧甘。是指把腳本文件中不必要的字節(jié)良拼,如空格和注釋統(tǒng)統(tǒng)刪除。有許多工具可以用來(lái)精簡(jiǎn)代碼充边。多數(shù)情況下你應(yīng)該有兩個(gè)版本庸推,一個(gè)是工作副本,可以修改代碼并添加注釋浇冰,另一個(gè)是精簡(jiǎn)副本贬媒,用于放在站點(diǎn)上,為了與非精簡(jiǎn)版本區(qū)分開(kāi)肘习,可在文件名中加上min字樣际乘。
第6章 案例研究:圖片庫(kù)改進(jìn)
1 圖片庫(kù)代碼回顧
2 平穩(wěn)退化
此代碼(見(jiàn)第5章)即使在JS功能被禁用,用戶也可以瀏覽圖片庫(kù)里的圖片漂佩,所有鏈接也都正常工作脖含。但如果選用“javascript:”偽協(xié)議,或把鏈接寫成#投蝉,禁用JS的用戶將無(wú)法瀏覽圖片器赞。
3 JS與HTML是分離的嗎
因?yàn)樵趆tml里插入了onclick事件,所以JS和HTML是混在在一起的墓拜。把JS移出HTML有多種方法港柜,如給每個(gè)鏈接添加class屬性。但注意圖片清單里各個(gè)鏈接有一個(gè)共同點(diǎn),他們都包含在同一個(gè)列表清單元素里夏醉,因此給列表清單設(shè)置一個(gè)id比較簡(jiǎn)單爽锥。
(1)添加事件處理函數(shù)。
想要完成的工作:
- 檢查當(dāng)前瀏覽器是否理解getElementsByTagName
- 檢查當(dāng)前瀏覽器是否理解getElementById
- 檢查當(dāng)前網(wǎng)頁(yè)是否有id為imagegallery的元素
- 遍歷imagegallery中的所有鏈接
- 設(shè)置onclick事件畔柔,讓它在有關(guān)鏈接被點(diǎn)擊時(shí)完成以下操作:把這個(gè)鏈接作為參數(shù)傳給showPic()函數(shù)氯夷,取消鏈接被點(diǎn)擊時(shí)的默認(rèn)行為。
①檢查點(diǎn)
if(!document.getElementsByTagName||!document.getElementById)return false;
if(!document.getElementById(“imagegallery”))return false;
出于JS與HTML分離的原則靶擦,如果想用JS給某個(gè)網(wǎng)頁(yè)添加一些行為腮考,就不應(yīng)該讓JS代碼對(duì)這個(gè)網(wǎng)頁(yè)的結(jié)構(gòu)有任何依賴。
②變量名里有什么
創(chuàng)建一個(gè)“gallery”變量玄捕,選擇一些有意義的單詞來(lái)命名可以讓代碼更容易閱讀和理解踩蔚。但要注意有些單詞在JS語(yǔ)言中有特殊的含義和用途,這些統(tǒng)稱為“保留字”的單詞不能用作變量名枚粘,另外馅闽,現(xiàn)有JS函數(shù)或方法的名字,如alert馍迄、var福也、if,也不能用來(lái)命名變量。
var galley=document.getElementById("imagegallery");
var links=gallery.getElementsByTagName("a");
③遍歷
把充當(dāng)循環(huán)計(jì)數(shù)器的變量命名為“i”是一種傳統(tǒng)做法攀圈,含義是increment(遞增)暴凑。
for(var i=0;i<links.length;i++){
④改變行為
links[i].onclick=function(){ /*定義匿名函數(shù)*/
showPic(this); /*this代表links[i]*/
return false; /*禁用鏈接默認(rèn)行為*/
}
⑤完成JS函數(shù)
function prepareGallery(){
if(!document.getElementsByTagName||!document.getElementById)return false;
if(!document.getElementById(“imagegallery”))return false;
var galley=document.getElementById("imagegallery");
var links=gallery.getElementsByTagName("a");
for(var i=0;i<links.length;i++){
links[i].onclick=function(){
showPic(this);
return false;
}
}
}
(2)共享onload事件。
如果DOM不完整赘来,則測(cè)試的準(zhǔn)確性就無(wú)從談起搬设。因此應(yīng)該讓這個(gè)函數(shù)在網(wǎng)頁(yè)加載完畢之后立刻執(zhí)行。網(wǎng)頁(yè)加載完畢會(huì)觸發(fā)onload事件撕捍,必須把prepareGallery函數(shù)綁定在這個(gè)事件上:window.onload=prepareGallery;
但如果想讓兩個(gè)函數(shù)都在頁(yè)面加載完成是執(zhí)行拿穴,分別與onload綁定,只有最后那個(gè)函數(shù)會(huì)執(zhí)行忧风。一個(gè)最簡(jiǎn)單的解決方法:創(chuàng)建一個(gè)匿名函數(shù)來(lái)容納這兩個(gè)函數(shù)默色,再將該匿名函數(shù)與onload綁定。一個(gè)彈性最佳的解決方法:利用addLoadEvent函數(shù)狮腿。
function addLoadEvent(func){
var oldonload=window.onload;
if(typeof window.onload!='function'{
window.onload=func;
}else{
window.onload=function(){
oldonload();
func();
}
}
}
4 不要做太多假設(shè)
之前的代碼里用到了id屬性值等于placeholder和description的元素腿宰,但未對(duì)這些元素是否存在做任何檢查。假如我們要實(shí)現(xiàn)缘厢,只要placeholder圖片存在吃度,即使description元素不存在,切換顯示新圖片的操作也照常進(jìn)行贴硫。
檢查placeholder:
if(!document.getElementById("placeholder"))return false;
description:
if(document.getElementById("description"));這樣是可選的椿每,有則執(zhí)行伊者,無(wú)則忽略。
添加這兩條代碼后间护,即使HTML中沒(méi)有id=placeholder也不會(huì)出現(xiàn)JS錯(cuò)誤亦渗,但是會(huì)出現(xiàn)點(diǎn)擊鏈接沒(méi)任何響應(yīng),這意味著腳本不能平穩(wěn)退化汁尺。問(wèn)題在于prepareGallery函數(shù)做出了這樣的假設(shè):showPic函數(shù)肯定會(huì)正常返回法精。基于這一假設(shè)痴突,prepareGallery函數(shù)取消了onclick事件的默認(rèn)行為搂蜓。是否返回false值以取消onclick事件的默認(rèn)行為,應(yīng)該由showPic函數(shù)決定辽装。如果圖片切換成功帮碰,返回true;如果圖片切換不成功,返回false如迟。應(yīng)該在返回前驗(yàn)證showPic的返回值,以決定是否組織默認(rèn)行為攻走。如果showPic返回true,則返回false阻止默認(rèn)行為殷勘;如果showPic返回false,則返回true允許默認(rèn)行為。
function prepareGallery(){
if(!document.getElementsByTagName||!document.getElementById)return false;
if(!document.getElementById("imagegallery"))return false;
var gallery=document.getElementById("imagegallery");
var links=gallery.getElementsByTagName("a");
for(var i=0;i<links.length;i++){
links[i].onclick=function(){
return !showPic(this);
}
}
}
5 優(yōu)化
showPic函數(shù)里仍存在一些需要處理的假設(shè)昔搂,如假設(shè)每個(gè)鏈接都有title屬性玲销。
if(whichpic.getAttribute("title") !=null)
作為一種簡(jiǎn)單的視覺(jué)反饋,把title不存在時(shí)的text設(shè)置為空字符串:
if(whichpic.getAttribute("title") !=null){
var text=whichpic.getAttribute("title");
} else {
var text="";
}
還可以寫成:
var text=whichpic.getAttribute("title")摘符?whichpic.getAttribute("title"):"";
這里的問(wèn)號(hào)叫三元操作符贤斜,其后是text的兩種取值:
variable=condition?if true:if false;
還可驗(yàn)證placeholder是否為圖片:
if(placeholder.nodeName!="IMG") return false;
注意nodeName總是返回一個(gè)大寫字母的值,即使元素在HTML中是小寫逛裤。
還可驗(yàn)證description的第一個(gè)子元素是文本:
if(description.firstChild.nodeType==3){
description.firstChild.nodeValue=text;
}
在實(shí)際工作中瘩绒,你要自己決定是否需要這些檢查,它們針對(duì)的是HTML中可能不在你控制范圍的內(nèi)情況带族。理想情況下不應(yīng)該對(duì)HTML的內(nèi)容和結(jié)構(gòu)做太多假設(shè)锁荔。
6 鍵盤訪問(wèn)
有些用戶不使用鼠標(biāo),使用鍵盤蝙砌,需調(diào)用onkeypress事件處理函數(shù)阳堕。要讓onkeypress和onclick觸發(fā)同樣的行為,可復(fù)制onclick代碼择克,或者links[i].onkeypress=links[i].onclick;但onkeypress很容易出問(wèn)題恬总。不過(guò)在幾乎所有瀏覽器里,用Tab鍵移動(dòng)到某個(gè)鏈接后按回車肚邢,也可觸發(fā)onclick氧秘。最好不要使用onkeypress溅呢,onclick對(duì)鍵盤訪問(wèn)的支持已很完美醋奠。最終代碼:
window.onload=prepareGallery;
function prepareGallery(){
if(!document.getElementsByTagName||!document.getElementById) return false;
if(!document.getElementById("imagegallery"))return false;
var gallery=document.getElementById("imagegallery");
var links=gallery.getElementsByTagName("a");
for(var i=0;i<links.length;i++){
links[i].onclick=function(){
return showPic(this)?false:true;
}
}
}
function showPic(whichpic){
if(!document.getElementById("placeholder")) return false;
var source = whichpic.getAttribute("href");
var placeholder = document.getElementById("placeholder");
if(placeholder.nodeName !="IMG") return false;
placeholder.setAttribute("src",source);
if(document.getElementById("description")){
var text = whichpic.getAttribute("title")? whichpic.getAttribute("title"):"";
var description = document.getElementById("description");
if (description.firstChild.nodeType==3){
description.firstChild.nodeValue = text;
}
}
return true;
}
7 把JS和CSS結(jié)合起來(lái)##
DOM Core和HTML-DOM##
至此用到的DOM方法:getElementsByTagName、getElementById记劈、getAttribute、setAttribute都是DOM Core的組成部分并巍,并不專屬于JS目木,支持DOM的任何一種程序語(yǔ)言都可以使用它們。使用JS和DOM為HTML文件編寫腳本時(shí)懊渡,還有許多屬性可供選用刽射,如onclick,這些屬性屬于HTML-DOM。例如HTML-DOM提供了一個(gè)forms對(duì)象剃执,它可以把document.getElementsByTagName("form")簡(jiǎn)化成document.forms誓禁。HTML-DOM代碼通常比DOM Core代碼簡(jiǎn)短,但它們只能用來(lái)處理Web文檔肾档∧∏。可根據(jù)個(gè)人喜好和具體情況進(jìn)行選擇。
第7章 動(dòng)態(tài)創(chuàng)建標(biāo)記
網(wǎng)頁(yè)的結(jié)構(gòu)由標(biāo)記負(fù)責(zé)創(chuàng)建怒见,絕大多數(shù)JS函數(shù)只用來(lái)改變某些細(xì)節(jié)而不改變其底層結(jié)構(gòu)俗慈。但JS也可以用來(lái)改變網(wǎng)頁(yè)的結(jié)構(gòu)和內(nèi)容。
1 傳統(tǒng)方法
(1)document.write
HTML:
<body>
<script>
document.write("<p>This is inserted.</p>");
</script>
</body>
其最大缺點(diǎn)是違背了“行為應(yīng)該與表現(xiàn)分離”的原則遣耍。即使把語(yǔ)句挪到外部函數(shù)里闺阱,也仍然要在<body>部分添加<script>來(lái)調(diào)用。最好用外部JS文件去控制網(wǎng)頁(yè)行為舵变,避免在<body>部分亂用<script>,避免使用document.write方法酣溃。
(2)innerHTML屬性
類似于document.write方法,innerHTML屬性也是HTML專有屬性纪隙,不能用于任何其他標(biāo)記語(yǔ)言文檔赊豌。任何時(shí)候,標(biāo)準(zhǔn)的DOM都可以替代innerHTML绵咱,雖然往往需要多編寫一些代碼亿絮,但DOM提供了更高的精確性和更強(qiáng)大的功能。
2 DOM方法
DOM不僅可以獲取文檔內(nèi)容麸拄,還可以更新文檔內(nèi)容派昧。如setAttibute,注意它并未改變文檔的物理內(nèi)容拢切,只有用瀏覽器打開(kāi)文檔是才會(huì)看到效果變化蒂萎,這是因?yàn)闉g覽器實(shí)際顯示的是那棵DOM節(jié)點(diǎn)樹(shù),在瀏覽器看來(lái)淮椰,DOM節(jié)點(diǎn)樹(shù)才是文檔五慈。所以你不是在創(chuàng)建標(biāo)記纳寂,而是在改變DOM節(jié)點(diǎn)樹(shù)。
(1)createElement方法
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="testdiv">
</div>
</body>
</html>
想把一段文本插入到testdiv中泻拦,用DOM語(yǔ)言說(shuō)毙芜,就是要?jiǎng)?chuàng)建一個(gè)p節(jié)點(diǎn),并將其作為div節(jié)點(diǎn)的一個(gè)子節(jié)點(diǎn)争拐。用createElement創(chuàng)建:
var para = document.createElement("p");
任何時(shí)候腋粥,只要使用了createElement,把新創(chuàng)建的元素賦給一個(gè)變量總是個(gè)好主意架曹。雖然p已經(jīng)存在隘冲,但它還不是任何DOM節(jié)點(diǎn)樹(shù)的組成部門,這種情況稱為文檔碎片绑雄,但它已經(jīng)像其他節(jié)點(diǎn)一樣展辞,有自己的DOM屬性了。
(2)appendChild方法
parent.appendChild(child) /*child不上引號(hào)*/
具體到上面的例子万牺,讓p稱為testdiv的子節(jié)點(diǎn):
var testdiv=document.getElementById("testdiv");
testdiv.appendChild(para);
雖然使用appendChild方法時(shí)罗珍,不必非得使用一些變量來(lái)引用父節(jié)點(diǎn)和子節(jié)點(diǎn),但這樣會(huì)提高代碼的可讀性脚粟。
(3)createTextNode方法
現(xiàn)在想把一些文本放入p元素覆旱,需要用createTextNode,語(yǔ)法與createElement類似珊楼。
var para = document.createElement("p");
var testdiv=document.getElementById("testdiv");
testdiv.appendChild(para);
var txt=document.createTextNode("Hello World");
para.createTextNode(txt);
appendChild方法還可以用來(lái)連接那些尚未成為文檔樹(shù)的節(jié)點(diǎn)通殃,所以可以先創(chuàng)建節(jié)點(diǎn)度液,再使用appendChild連接厕宗。
(4)一個(gè)更復(fù)雜的組合
如果要插入<p>This is <em>my</em> content.</p>,先分析節(jié)點(diǎn)樹(shù)再寫代碼:
window.onload=function(){
var para=document.createElement("p");
var txt1=document.createTextNode("This is ");
var emphasis=document.createElement("em");
var txt2=document.createTextNode("my ");
var txt3=document.createTextNode("content.");
para.appendChild(txt1);
para.appendChild(emphasis);
para.appendChild(txt3);
emphasis.appendChild(txt2);
var testdiv=document.getElementById("testdiv");
testdiv.appendChild(para);
}
3 重回圖片庫(kù)
之前圖片庫(kù)的HTML中有一個(gè)圖片和一段文字的存在只是為了讓DOM處理,那么用DOM方法來(lái)創(chuàng)建它們是最合適的選擇堕担。
需要完成的任務(wù):
- 創(chuàng)建一個(gè)img元素節(jié)點(diǎn)
- 設(shè)置這個(gè)節(jié)點(diǎn)的id屬性
- 設(shè)置這個(gè)節(jié)點(diǎn)的src屬性
- 設(shè)置這個(gè)節(jié)點(diǎn)的alt屬性
- 創(chuàng)建一個(gè)p元素節(jié)點(diǎn)
- 設(shè)置這個(gè)節(jié)點(diǎn)的id屬性
- 創(chuàng)建一個(gè)文本節(jié)點(diǎn)
- 把這個(gè)文本節(jié)點(diǎn)追加到p元素上
- 把p元素和img元素插入到gallery.html文檔
var placeholder=document.createElement("img");
placeholder.setAttribute("id","placeholder");
placeholder.setAttribute("src","images/show.jpg");
placeholder.setAttribute("alt","my image gallery");
var description=document.createElement("p");
description.setAttribure("id","description");
var desctext=document.createTextNode("Choose an image");
description.appendChild(desctext);
document.body.appendChild(placeholder);
document.body.appendChild(description);
(1)在已有元素前插入一個(gè)新元素
原HTML文檔中圖片清單剛好在文檔最后已慢,所以把placeholder和description追加到body節(jié)點(diǎn)上,它們會(huì)出現(xiàn)在清單后面霹购。如果想把一個(gè)新元素插入到一個(gè)現(xiàn)有元素的前面佑惠,可用insertBefore()方法實(shí)現(xiàn):
parentElement.insertBefore(newElement,targetElement)
其實(shí)不用搞清楚parentElement是哪個(gè),因?yàn)閠argetElement的parentNode屬性值就是它齐疙。
gallery.parentNode.insertBefore(description,gallery);
(2)在現(xiàn)有方法后插入一個(gè)新元素
DOM沒(méi)有提供insertAfter方法膜楷,但完全可以用DOM方法編寫一個(gè)insertAfter方法。思路贞奋,查看目標(biāo)元素是不是parent的lastChild,如果是赌厅,直接appendChild;如果不是轿塔,就插入到目標(biāo)元素下一個(gè)兄弟元素的前面特愿。
function insertAfter(newElement,targetElement){
var parent=targetElement.parentNode;
if(parent.lastChild==targetElement){
parent.appendChild(newElement);
}else{
parent.insertBefore(newElement,targetElement.nextSibling);
}
(3)圖片庫(kù)二次改進(jìn)
4 Ajax
2005年發(fā)明仲墨,用于概括異步加載頁(yè)面內(nèi)容的技術(shù)。使用Ajax可以做到只更新頁(yè)面中的一小部分揍障,不必再次加載整個(gè)頁(yè)面目养。對(duì)頁(yè)面的請(qǐng)求以異步方式發(fā)送到服務(wù)器,服務(wù)器不會(huì)用整個(gè)頁(yè)面來(lái)響應(yīng)請(qǐng)求毒嫡,會(huì)在后來(lái)處理請(qǐng)求癌蚁,用戶此時(shí)仍能繼續(xù)瀏覽頁(yè)面并與頁(yè)面交互。
(1)XMLHttpRequest對(duì)象
它是Ajax技術(shù)的核心审胚,充當(dāng)瀏覽器的腳本與服務(wù)器之間的中間人匈勋。JS通過(guò)這個(gè)對(duì)象可以自己發(fā)送請(qǐng)求和處理響應(yīng)。由于不同瀏覽器實(shí)現(xiàn)該對(duì)象的方式不太一樣膳叨,因此需要為同一事情寫不同的代碼分支洽洁。