[筆記7]JavaScript DOM編程藝術(shù)_圖片庫(kù)改進(jìn)版

勤于思考是每位有創(chuàng)新精神的網(wǎng)頁(yè)設(shè)計(jì)人員都應(yīng)該具備的特質(zhì)第美。

平穩(wěn)退化

第一個(gè)問(wèn)題增显,如果JS功能被禁用易稠,會(huì)怎么樣拿霉?把href屬性設(shè)置為一個(gè)真實(shí)存在的值吟秩,能夠讓之前提到的圖片庫(kù)平穩(wěn)退化。

JS與HTML標(biāo)記是分離的嗎绽淘?

第二個(gè)問(wèn)題涵防,網(wǎng)頁(yè)的行為層(JS)是作用于其結(jié)構(gòu)層(HTML)之上的么?還是兩種代碼混雜在一起收恢?

  • 必須找到一種“掛鉤”把JS代碼與HTML文檔中的有關(guān)標(biāo)記關(guān)聯(lián)起來(lái)武学。在頁(yè)面元素上設(shè)置class和id是常見(jiàn)的方式,應(yīng)該合理設(shè)置這些類型伦意,少為佳火窒。

添加事件處理函數(shù)

現(xiàn)在我需要編寫(xiě)一個(gè)簡(jiǎn)短的函數(shù)把有關(guān)操作關(guān)聯(lián)到onclick事件上,函數(shù)命名為prepareGallery

  • 檢查當(dāng)前瀏覽器是否理解getElementsByTagName
  • 檢查當(dāng)前瀏覽器是否理解getElementById
  • 檢查當(dāng)前網(wǎng)頁(yè)是否存在一個(gè)id為imagegallery的元素
  • 遍歷imagegallery元素中的所有鏈接
  • 設(shè)置onclick事件驮肉,讓它在有關(guān)鏈接被點(diǎn)擊時(shí)完成以下操作熏矿。
    • 把這個(gè)鏈接作為參數(shù)傳遞給showPic函數(shù)
    • 取消鏈接被點(diǎn)擊時(shí)的默認(rèn)行為,不讓瀏覽器打開(kāi)這個(gè)鏈接
      檢查點(diǎn)
var supported=document.getElementsByTagName&&document.getElementById;
if(!supported)return;
//更加針對(duì)的檢查
if(!document.getElementById("imagegallery")){
   return false;
}

作為一條原則离钝,如果想用JS給某個(gè)網(wǎng)頁(yè)添加一些行為票编,就不應(yīng)該讓JS代碼對(duì)這個(gè)網(wǎng)頁(yè)結(jié)構(gòu)有任何依賴。

整理后的代碼如下:

function prepareGallery(){
   if(!document.getElementsByTagName) return false;
   if(!document.getElementById)return false;
   if(!document.getElementById("imagegallery"))return false;
}

變量名里有什么
使用變量名進(jìn)行對(duì)象的臨時(shí)存儲(chǔ)卵渴。

function prepareGallery(){
   if(!document.getElementsByTagName) return false;
   if(!document.getElementById)return false;
   if(!document.getElementById("imagegallery"))return false;
   var gallery=document.getElementById("imagegallery");
   var links=gallery.getElementsByTagName("a");
}

遍歷
改變行為

function prepareGallery(){
   if(!document.getElementsByTagName) return false;
   if(!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(){
        showPic(this);
        return false;
    }
   }
}

共享onload事件

讓函數(shù)在網(wǎng)頁(yè)加載完畢后立即執(zhí)行慧域。

PS:但是如果存在多個(gè)函數(shù),需要在網(wǎng)頁(yè)加載完畢之后執(zhí)行浪读,可以先創(chuàng)建一個(gè)匿名函數(shù)來(lái)容納這兩個(gè)函數(shù)昔榴,然后把這兩個(gè)匿名函數(shù)綁定到onload事件上。

window.onload=function(){
    firstFunction();
    secondFunction();
}

這里還有一個(gè)彈性最佳的解決方案碘橘。使用addLoadEvent互订,它只有一個(gè)參數(shù),打算在頁(yè)面加載完畢時(shí)執(zhí)行函數(shù)的名字痘拆。

addLoadEvent函數(shù)將要完成的操作仰禽。

  • 把現(xiàn)有的window.onload事件處理函數(shù)的值存入變量oldonload
  • 如果在這個(gè)處理函數(shù)上海沒(méi)有綁定任何函數(shù),就像平時(shí)那樣把新函數(shù)添加給它纺蛆。
  • 如果在這個(gè)處理函數(shù)上已經(jīng)綁定了一些函數(shù)吐葵,就把新函數(shù)追加到現(xiàn)有指令的末尾。

addLoadEvent函數(shù)的代碼清單桥氏。

function addLoadEvent(func){
 var oldonload=window.onload;
 if(typeof window.onload!='function'){
    window.onload=func;
 }else{
    window.onload=function(){
        oldonload();
        func();
    }
 }
}

//上面的代碼我們就可以這樣實(shí)現(xiàn)折联。
addLoadEvent(firstFunction);
addLoadEvent(secondFunction);

不要做太多的假設(shè)

在代碼里用到了id屬性值等于palceholder和description的元素,但我并未對(duì)這些元素是否存在做任何檢查识颊。我們需要增加一些語(yǔ)句來(lái)檢查這些元素是否存在。

function showPic(whichpic) {
    if(!document.getElementById("placeholder"))return false;
    var source=whichpic.getAttribute("href");
    var placeholder=document.getElementById("placeholder");
    placeholder.setAttribute("src",source);
    if(document.getElementById("description")){
    var text=whichpic.getAttribute("title");
    var description=document.getElementById("description");
    description.firstChild.nodeValue=text;
    }
    return true;
}

改進(jìn)后的showPic函數(shù)不再假設(shè)有關(guān)標(biāo)記文檔里肯定存在著placeholder圖片和description元素,即使沒(méi)有placeholder圖片祥款,也不會(huì)發(fā)生任何JS錯(cuò)誤清笨。但是有一個(gè)問(wèn)題就是如果把placeholder圖片從標(biāo)記文檔里刪掉并在瀏覽器里刷新這個(gè)頁(yè)面,就會(huì)出現(xiàn)無(wú)論點(diǎn)擊清單里的哪一個(gè)鏈接刃跛,都沒(méi)有任何響應(yīng)抠艾。
原因在于showPic函數(shù)肯定會(huì)正常返回,基于這一假設(shè)桨昙,prepareGallery函數(shù)取消了onclick事件的默認(rèn)行為检号。

links[i].onclick=function(){
        showPic(this);
        return false;
    }

是否要返回一個(gè)false值來(lái)取消onclick事件的默認(rèn)行為,應(yīng)該由showPic函數(shù)決定蛙酪。showPic應(yīng)返回兩個(gè)可能的值齐苛。

  • 如果圖片切換成功,返回true桂塞。
  • 如果圖片切換不成功凹蜂,返回false。

源碼鏈接:

優(yōu)化

盡管代碼已經(jīng)相當(dāng)完善了阁危,在showPic函數(shù)里仍存在一些需要處理的假設(shè)玛痊。

  • 檢查title屬性是否真的存在
if(whichpic.getAttribute("title")!=null)
或者
if(whichpic.getAttribute("title"))
代碼優(yōu)化如下:
var text=whichpic.getAttribute("tilte")?whichpic.getAttribute("title"):"";
  • 檢查placeholder元素是否存在
if(placeholder.nodeName!="IMG")return false;

請(qǐng)注意,nodeName屬性總是返回一個(gè)大寫(xiě)字母的值狂打,即使元素在HTML文檔中是小寫(xiě)字母擂煞。
-對(duì)description元素的第一個(gè)子元素是一個(gè)文本節(jié)點(diǎn)進(jìn)行檢查。

if(description.firstChild.nodeType==3){
  description.firstChild.nodeValue=text;
}

優(yōu)化后的代碼如下:

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;
}

PS:在實(shí)際工作中趴乡,你要自己決定是否真的需要這些檢查对省。它們針對(duì)的是HTML文檔有可能不在你控制范圍內(nèi)的情況。

鍵盤訪問(wèn)

在有關(guān)onclick事件處理的腳本中浙宜,有一項(xiàng)優(yōu)化工作是不能不考慮的官辽。

公所周知,不使用鼠標(biāo)也可以瀏覽Web粟瞬。鍵盤上的Tab鍵可以讓我們從這個(gè)鏈接移動(dòng)到另一個(gè)鏈接同仆,而按下回車鍵將啟用當(dāng)前鏈接。有個(gè)名叫onkeypress的事件處理函數(shù)是專門用來(lái)處理鍵盤事件的裙品。按下鍵盤上任何一個(gè)按鍵都會(huì)觸發(fā)onkeypress事件俗批。

一種簡(jiǎn)單的方法:
可以確保onkeypress模仿onclick事件行為。

links[i].onkeypress=links[i].onclick;

小心onkeypress

最后的決定是不添加onkeypress事件處理函數(shù)市怎。原因是這個(gè)事件處理函數(shù)很容易出問(wèn)題岁忘。用戶每按下一個(gè)案件都會(huì)觸發(fā)它。
onclick事件與鼠標(biāo)點(diǎn)擊動(dòng)作相關(guān)聯(lián)的感覺(jué)区匠。事實(shí)卻并非如此干像。在幾乎所有瀏覽器里帅腌,用tab鍵移動(dòng)到某個(gè)鏈接然后按下回車鍵的動(dòng)作也會(huì)觸發(fā)onclick事件。從這點(diǎn)看來(lái)麻汰,把它命名為onactivate更恰當(dāng)速客。

最好不要使用onkeypress事件處理函數(shù)。onclick事件處理函數(shù)已經(jīng)能滿足需要五鲫,雖然它叫做onclick溺职,但是它對(duì)鍵盤的訪問(wèn)支持相當(dāng)完美。

最終代碼:

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;
}

function prepareGallery(){
   if(!document.getElementsByTagName) return false;
   if(!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);
    }
   }
}

把JS與CSS結(jié)合起來(lái)

把內(nèi)嵌型事件處理函數(shù)移出標(biāo)記文檔時(shí)位喂,我在文檔里為JS代碼留下了一個(gè)“掛鉤”浪耘,如<ul id="imagegallery">,這個(gè)掛鉤完全可以用在CSS樣式表里塑崖。

DOM Core和HTML-DOM

在編寫(xiě)JS代碼時(shí)只用到以下幾個(gè)DOM方法七冲。

  • getElementById
  • getElementByTagName
  • getAttribute
  • setAttribute
    這些方法都是DOM Core的組成部分。它們并不專屬于JS弃舒,支持DOM的任何一種程序設(shè)計(jì)語(yǔ)言都可以使用它們癞埠。它們的用途也并非僅限于處理網(wǎng)頁(yè),它們可以用來(lái)處理用任何一種標(biāo)記語(yǔ)言編寫(xiě)出來(lái)的文檔聋呢。

PS:在Web文檔中苗踪,同樣的代碼即可以使用DOM來(lái)編寫(xiě),也可以使用HTML-DOM來(lái)編寫(xiě)削锰。通常情況下通铲,HTML-DOM的語(yǔ)句更簡(jiǎn)短。如:var source=whichpic.getAttribute("href");可以使用HTML-DOM達(dá)到同樣目的的語(yǔ)句:var source=whichpic.href;

結(jié)構(gòu)與行為的分離程度越大越好器贩。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颅夺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子蛹稍,更是在濱河造成了極大的恐慌吧黄,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唆姐,死亡現(xiàn)場(chǎng)離奇詭異拗慨,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)奉芦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門赵抢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人声功,你說(shuō)我怎么就攤上這事烦却。” “怎么了先巴?”我有些...
    開(kāi)封第一講書(shū)人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵其爵,是天一觀的道長(zhǎng)冒冬。 經(jīng)常有香客問(wèn)我,道長(zhǎng)摩渺,這世上最難降的妖魔是什么窄驹? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮证逻,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘抗斤。我一直安慰自己囚企,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布瑞眼。 她就那樣靜靜地躺著龙宏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪伤疙。 梳的紋絲不亂的頭發(fā)上银酗,一...
    開(kāi)封第一講書(shū)人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音徒像,去河邊找鬼黍特。 笑死,一個(gè)胖子當(dāng)著我的面吹牛锯蛀,可吹牛的內(nèi)容都是我干的灭衷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼旁涤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼翔曲!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起劈愚,我...
    開(kāi)封第一講書(shū)人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瞳遍,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后菌羽,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掠械,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年算凿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了份蝴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡氓轰,死狀恐怖婚夫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情署鸡,我是刑警寧澤案糙,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布限嫌,位于F島的核電站,受9級(jí)特大地震影響时捌,放射性物質(zhì)發(fā)生泄漏怒医。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一奢讨、第九天 我趴在偏房一處隱蔽的房頂上張望稚叹。 院中可真熱鬧,春花似錦拿诸、人聲如沸扒袖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)季率。三九已至,卻和暖如春描沟,著一層夾襖步出監(jiān)牢的瞬間飒泻,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工吏廉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留泞遗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓迟蜜,卻偏偏與公主長(zhǎng)得像刹孔,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子娜睛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容