用探測技術編寫跨瀏覽器的Javascript代碼

來源:互聯網
上載者:User

作者:Tony Ross(Program Manager)
原文:Same Markup: Writing Cross-Browser Code
翻譯:一回(csser.com)

基本原則
  • 推薦

    • 功能探測:使用某個功能前先檢測瀏覽器是否支援它
    • 行為探測:在應用之前對已知問題進行測試
  • 不推薦
    • 探測指定瀏覽器:根據瀏覽器的唯一性來改變頁面行為
    • 臆斷不相關的功能:根據一個功能的探測去應用另一個不同的功能

上面所列的原則很重要,原因是當今的大部分頁面都會混合適合不同瀏覽器的代碼,這些混合代碼用於判斷什麼情況下運行哪些程式,以適合不同的瀏覽器,最基本的就是指令碼判斷,通常看起來像下面的樣子

if ( condition ) {
// 主要代碼 csser.com
} else {
// 備用代碼
}

上面代碼用到的判斷條件(condition),很多情況下不是基於一個給定的功能是否可用,而是基於使用者使用的哪個瀏覽器,這樣會存在一個問題: 備用代碼是基於指定的瀏覽器而執行,從而限制了網頁的適應性。最終結果將是一旦新的瀏覽器發布,頁面功能將會受影響。同時另外的情況是,即使新版本瀏覽器 增加了新的功能,代碼仍將沿用舊的方法,我們通過下面的例子來說明這個問題:

事件註冊樣本(基於瀏覽器探測的實現:不推薦)

你可以很容易的測試下面代碼的效果,範例程式碼通過探測瀏覽器(差的實踐)切換事件模型。

 

// 事件處理樣本函數
function f1() { document.write("addEventListener was used by csser.com"); }
function f2() { document.write("attachEvent was used by csser.com"); }

// 不被推薦:探測指定瀏覽器
if(navigator.userAgent.indexOf("MSIE") == -1) {
window.addEventListener("load", f1, false);
} else {
window.attachEvent("onload", f2);
}


結果,IE9下輸出:attachEvent was used by csser.com。很明顯,即使IE9已經支援addEventListener,但仍然不會被使用

事件註冊樣本(基於功能探測的實現:推薦)

下面的代碼通過功能探測切換事件模型,與檢測IE瀏覽器不同的是,它檢測addEventListener功能是否可用,該代碼不僅在不支援 addEventListener的古代瀏覽器下可用,更重要的是,只要瀏覽器支援addEventListener功能就可以被使用。

 

// 事件處理樣本函數
function f1() { document.write("addEventListener was used by csser.com"); }
function f2() { document.write("attachEvent was used by csser.com"); }

// 推薦:功能探測
if(window.addEventListener) {
window.addEventListener("load", f1, false);
} else if ( window.attachEvent ) {
window.attachEvent("onload", f2);
}


要做到讓適合的代碼在適合的瀏覽器下運行,這就是為什麼功能探測在網頁和架構中越來越多被採用的原因。功能探測允許跨瀏覽器的代碼順利的執行,而不 需要你完全弄明白不同瀏覽器的不同版本的具體能力。jQuery就是一個幾乎完全依賴功能探測的Javascript架構,事實上,jQuery.support文檔詳細的向我們介紹了如何在你的網站使用功能探測。

行為探測(jQuery的getElementById樣本:推薦)

除了直接的功能探測,jQuery也利用了行為探測,它通過運行一段存在已知問題的代碼來確定是否需要變通的解決方案。下面的是從jQuery源代 碼取出的經過修改的片段,其用途是測試getElementById是否返回包含相同name特性的元素,這是古老IE瀏覽器的Bug,IE8已經修複。

 

// 動態建立一個包含name特性的超連結元素,並放置在動態建立的div元素內
// 文檔中該a元素的name值是唯一的
var form = document.createElement("div"),
id = "script" + (new Date).getTime();
form.innerHTML = "<a name='" + id + "'/>";

// 將建立的div元素插入頁面文檔的最前端
var root = document.documentElement;
root.insertBefore( form, root.firstChild );

// 通過getElementById傳入唯一的id值,如果存在匹配的元素,說明返回了name值的元素
if ( document.getElementById( id ) ) {
// ... 代碼...
// 用於測試的代碼
document.write("getElementById workaround was used by csser.com");
}
// 用於測試的代碼
else document.write("No workaround was used by csser.com");
root.removeChild( form );
臆斷不相關的功能(可實踐性:差)

最後一點我需要講到的是,臆斷不相關的功能,先上代碼,然後看看在不同IE版本瀏覽器下的結果:

 

// try-catch語句塊用於捕捉IE8下的執行錯誤
try {
function fn() {alert("www.csser.com");}
if(window.postMessage) {
window.addEventListener("message", fn, false);
// 範例程式碼
document.write("Message事件註冊成功");
} else {
// 當postMessage不可用時的代碼
// 範例程式碼
document.write("不支援postMessage功能");
}
} catch(e) {
document.write("Message事件註冊失敗");
}

上例的代碼在IE7-9下的執行結果分別為:

IE7 :不支援postMessage功能

IE8 : Message事件註冊失敗

IE9 : Message事件註冊成功

本樣本中的錯誤在於,編寫者認為瀏覽器支援postMessage就會支援addEventListener,但事實上postMessage功能在IE8就被支援,但addEventListener是從IE9才被加入的。經過正確修複的代碼如下:

 

function fn() {alert("www.csser.com");}
if(window.postMessage) {
if(window.addEventListener) {
window.addEventListener("message", fn, false);
} else if(window.attachEvent) {
window.attachEvent("onmessage", fn);
}
// 範例程式碼
document.write("Message事件註冊成功");
} else {
// 當postMessage不可用時的代碼
// 範例程式碼
document.write("不支援postMessage功能");
}


 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.