本章內容
- 平穩退化 確保網頁在沒有JS的情況下也能正常工作。
- 分離JS 把網頁的結構和內容與JS腳本的動作行為分開
- 向后兼容性 確保老版本的瀏覽器不會因為你的JS腳本而死掉
- 性能考慮 確定腳本執行的性能最優
平穩退化
如果正確地使用了JS腳本,就可以讓訪問者在他們的瀏覽器不支持JS的情況下仍能順利地瀏覽你的網站,這就是平穩退化
JS使用window對象的open()方法來創建新的瀏覽器窗口。這個方法有三個參數:window.open(url,name,features)
- url新窗口里打開的網頁的URL地址
- 新窗口的名字,可以在代碼里通過這個名字與新窗口進行通信。
- 以逗號分隔的字符串。其內容是新窗口的各種屬性。
function popUp(winURL) {
window.open(winURL,"popUp","width=320,height=480");
}
調用popUp函數的一個辦法就是使用偽協議。
真協議用來在因特網上的計算機之間傳遞數據包,如http協議、ftp協議。偽協議是一種非標準化的協議。“javascript:”偽協議讓我們通過一個鏈接來調用JS函數。
具體做法:
<a href="javascript:popUp('http://www.baidu.com/');">Example</a>
這條語句在支持“javascript:”偽協議的瀏覽器中運行正常,較老的瀏覽器則會嘗試打開鏈接失敗,支持這種偽協議但禁用了JS功能的瀏覽器會什么也不做。
總之,在html文檔里通過javascript:偽協議調用JavaScript代碼的做法非常不好。
內嵌的事件處理函數
把onclick事件處理函數作為屬性嵌入a標簽,改處理函數將在onclick事件發生時調用圖片切換函數。
<a href="#" onclick="popUp('http://www.example.com');return false;">Example</a>
因為在上面這條HTML指令里使用了return false語句,這個鏈接不會被真的打開。“#”符號是一個僅供文檔內部使用的鏈接符號。把href屬性值設置為“#”只是為了創建一個空鏈接。實際工作全部由onclick屬性負責完成。
但是上面的技巧都不能平穩的退化,如果用戶已經禁用了瀏覽器的JS功能,這樣的鏈接毫無用處。
具體到popUp()函數,為其中的JS代碼預留出退路很簡單。在鏈接里把href屬性設置為真實存在的URL地址,讓它成為一個有效的鏈接。
<a onclick="popUp('http://www.example.com';return false;)">Example</a>
//-------------用this簡化一下-------------//
<a onclick="popUp(this.getAttribute('href');return false;)">Example</a>
//-------------更簡單的方式-------------//
<a onclick="popUp(this.href);return false">Example</a>
在本書此前介紹的所有技巧當中,這個技巧最有用,但是它還有改進的余地。最明顯的不足時:每當需要打開新窗口時,就不得不把一些JS代碼嵌入標記文檔中。如果能把事件處理函數在內的所有JS代碼全都放在外部文件里,這個技巧將更加完善
向CSS學習
CSS是一項了不起的技術。CSS可以讓人們對網站設計工作中的各個方面做出嚴格細致的控制。
標記良好的內容就是一切
PS:上面這句話深有感觸。
分離JS
JS語言不要求事件必須在HTML文檔里處理。我們可以在外部JS文件里吧一個事件添加到HTML文檔中的某個元素上。element.event=action...
關鍵是怎樣才能把應該獲得這個事件的元素確定下來。這個問題可以利用class或者id來解決。
如果想把一個事件添加到某個帶有特定id屬性的元素上,用getElementById就可以解決問題:getElementById(id).event=action。如果事件涉及到多個元素,我們可以用getElmentsByTagName和getAttribute把事件添加到有著特定屬性的一組元素上。
具體步驟:
- 把文檔里的所有鏈接全放入一個數組里。
- 遍歷數組。
- 如果某個鏈接的class屬性等于popup,就表示這個鏈接在被點擊時應該調用popUp()函數。
于是,
- 把這個鏈接的href屬性值傳遞給popUp()函數;
- 取消這個鏈接的默認行為,不讓這個鏈接把訪問者帶離當前窗口。
var links=document.getElementByTagName("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;
}
}
}
如果把上面這段代碼存入外部JS文件中,它們將無法正常運行。因為代碼的第一行是var links=document.getElementsByTagName("a");這句話將在JS文件被加載時立刻執行。如果JS文件是從HTML文檔的< head>部分用<script>標簽調用的,它將在HTML文檔之前加載到瀏覽器里。同樣,如果標簽位于文檔底部</body>之前,就不能保證哪個文件最先結束加載(瀏覽器可能加載多個),因為腳本加載時文檔可能不完整,所以模型也不完整,沒有完整的DOM,getElementByTagName等方法就不能正常工作。必須讓這些代碼在HTML文檔全部加載到瀏覽器之后馬上開始執行。
HTML文檔加載完畢時將觸發一個事件,文檔將被加載到一個瀏覽器窗口里,document對象又是window對象。當window對象觸發onload事件時,document對象已經存在
window.onload=prepareLinks;
funciton 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;
}
}
}
}
向后兼容
對象檢測
判斷瀏覽器是否對DOM支持,最簡單的解決方案是,檢測瀏覽器對JS的支持程度。解決方案:只要把某個方法打包在一個if語句中,就可以根據這條if語句的條件表達式的求值結果是true還是false來決定采取怎樣的行動。這種檢測稱為對象檢測。
例如,如果有一個使用了getElementById()方法的函數,就可以在調用getElementById()方法之前先檢查用戶所使用的瀏覽器是否支持這個方法。**在使用對象檢測時,一定要刪掉方法后面的圓括號,如果不刪掉,測試的將是方法的結果。無論方法是否存在。
function myFunction(){
if(document.getElementById){
statements using getElementById
}
}
為了避免上面的方法,增加邏輯的深度,可以使用下面的方式。
if(!getElementById){
return false;
}
//------------如果要檢測多個方法或著屬性是否存在,可以使用“邏輯或”
if(!getElementById||!getElementByTagBName){
return false;
}
上面的例子增加JS是否支持DOM的語句如下:
window.onload=prepareLinks;
function prepareLinks(){
if (!document.getElementsByTagName) {return false;}
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;
}
}
}
}
瀏覽器嗅探技術
瀏覽器嗅探 指通過提取瀏覽器供應商提供的信息來解決向后兼容問題。從理論上講,可以通過JS代碼檢索關于瀏覽器品牌和版本的信息,這些信息可以用來改善JS腳本代碼的向后兼容性。
PS:瀏覽器嗅探技術充滿風險,逐漸被對象檢測技術所取代。主要是兩個原因,一個是瀏覽器會撒謊,你無法獲得準確的版本或者品牌信息。第二是瀏覽器嗅探器腳本是對版本信息進行精確匹配,版本信息變化太快,腳本所做的修好會比較多。
性能考慮
盡量少訪問DOM和盡量減少標記
訪問DOM方式對腳本性能會產生非常大的影響。不管什么時候,只要查詢DOM中某些元素,瀏覽器都會搜索整個DOM樹,從中查找可能匹配的元素。
另一個需要注意的地方,就是要盡量減少文檔中的標記數量。過多不必要的元素只會增加DOM樹的規模,進而增加遍歷DOM樹以查找特定元素的時間。
合并和放置腳本
將多個js文件合并到一個文件中,這樣就可以減少加載頁面時發送的請求數量。而減少請求數量通常都是在性能優化時首先要考慮的。
把所有script標簽都放到文檔的末尾,body標記之前,就可以讓頁面變得更快。
壓縮腳本
壓縮腳本可以加快加載速度。
所謂壓縮腳本,指的是把腳本文件中不必要的字節,如空格和注釋,統統刪掉,從而達到壓縮文件的目的。精簡后的代碼雖然不容易看懂,卻能大幅減少文件大小。多數情況下,你應該有兩個版本。一個是工作副本,可以修改代碼并添加注釋;另一個是精簡副本,用于放在站點上。通常為了將精簡版本與非精簡版本區分開,最好在精簡副本的文件名上加上min字符。
推薦的幾個代表性的代碼壓縮工具:
- Douglas Crockford的JSMin(http://www.crockford.com)
- 谷歌的Closure Compiler(http://closure-compiler.appspot.com/home)