javascript快速入門21--DOM總結

跨瀏覽器開發

市場上的瀏覽器種類多的不可勝數,它們的解釋引擎各不相同,期待全部瀏覽器都一致的支持JavaScript,CSS,DOM,那要等到不知何時,然而開發者不能幹等着那天。歷史上已經有很多方法來解決瀏覽器兼容問題了,主要分爲兩種:1.userAgent字符串檢測,2.對象檢測;固然,也不能考慮全部的瀏覽器,咱們須要按照客戶需求來,若是能夠確信瀏覽網站的用戶都使用或大部分使用IE瀏覽器,那麼你大可放心的使用IE專有的那些豐富的擴展,固然,一旦用戶開始轉向另外一個瀏覽,那麼痛苦的日子便開始了。下面是市場上的主流瀏覽器列表:javascript

  • Internet Explorer
  • Mozilla Firefox
  • Google Chrome
  • Opera
  • Safari

注意,瀏覽器老是不斷更新,咱們不但要爲多種瀏覽器做兼容處理,還要對同一瀏覽器多個版本做兼容處理。好比IE瀏覽器,其6.0版本和7.0版本都很流行,由於微軟IE隨着操做系統綁定安裝(以前也是同步發行,微軟平均每兩年推出一款我的桌面,一樣IE也每兩年更新一次;直到如今,因爲火狐的流行,IE工做組才加快IE的更新),因此更新的較慢,6.0版和7.0版有很大差異。css

市場上還存在一些其它瀏覽器,但因爲它們都是使用的上面所列瀏覽器的核心,或與上面瀏覽器使用了相同的解釋引擎,因此無需多做考慮。下面是主流的瀏覽器解釋引擎列表:html

  1. Trident

    Trident (又稱爲MSHTML),是微軟的窗口操做系統(Windows)搭載的網頁瀏覽器—Internet Explorer的排版引擎的名稱,它的第一個版本隨着1997年10月Internet Explorer第四版釋出,以後不斷的加入新的技術並隨着新版本的Internet Explorer釋出。在將來最新的Internet Explorer第七版中,微軟將對Trident排版引擎作了的重大的變更,除了加入新的技術以外,並增長對網頁標準的支持。儘管這些變更已經在至關大的程度上落後了其它的排版引擎。使用該引擎的主要瀏覽器:IE,TheWorld,MiniIE,Maxthon,騰訊TT瀏覽器。事實上,這些瀏覽器是直接使用了IE核心,由於其userAgent字符串中返回的信息與IE是如出一轍的!java

  2. Gecko

    壁虎,英文爲"Gecko"。Gecko是由Mozilla基金會開發的佈局引擎的名字。它本來叫做NGLayout。Gecko的做用是讀取諸如HTML、CSS、XUL和JavaScript等的網頁內容,並呈現到用戶屏幕或打印出來。Gecko已經被許多應用程序所使用,包括若干瀏覽器,例如Firefox、Mozilla Suite、Camino,Seamonkey等等ajax

  3. Presto

    Presto是一個由Opera Software開發的瀏覽器排版引擎,供Opera 7.0及以上使用。Presto取代了舊版Opera 4至6版本使用的Elektra排版引擎,包括加入動態功能,例如網頁或其部分可隨着DOM及Script語法的事件而從新排版。Presto在推出後不斷有更新版本推出,使很多錯誤得以修正,以及閱讀Javascript效能得以最佳化,併成爲速度最快的引擎。編程

  4. KHTML

    是HTML網頁排版引擎之一,由KDE所開發。KDE系統自KDE2版起,在檔案及網頁瀏覽器使用了KHTML引擎。該引擎以C++編程語言所寫,並以LGPL受權,支援大多數網頁瀏覽標準。因爲微軟的Internet Explorer的佔有率至關高,很多以FrontPage製做的網頁均包含只有IE才能讀取的非標準語法,爲了使KHTML引擎可呈現的網頁達到最多,部分IE專屬的語法也一併支援。目前使用KHTML的瀏覽器有Safari和Google Chrome。而KHTML也產生了許多衍生品,如:WebKit,WebCore引擎瀏覽器

利用userAgent檢測

下面是各大瀏覽器使用彈窗顯示的userAgent字符串閉包

IE瀏覽器:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)框架

火狐瀏覽器:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9.0.4) Gecko/2008102920 Firefox/3.0.4異步

Opera瀏覽器:Opera/9.64 (Windows NT 5.1; U; Edition IBIS; zh-cn) Presto/2.1.1

Safari瀏覽器:Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/528.16 (KHTML, like Gecko) Version/4.0 Safari/528.16

Google Chrome瀏覽器:Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/530.5 (KHTML, like Gecko) Chrome/2.0.172.33 Safari/530.5

可使用下面的代碼進行瀏覽器檢測

    var Browser = {
        isIE:navigator.userAgent.indexOf("MSIE")!=-1,
        isFF:navigator.userAgent.indexOf("Firefox")!=-1,
        isOpera:navigator.userAgent.indexOf("Opera")!=-1,
        isSafari:navigator.userAgent.indexOf("Safari")!=-1
    };

 

但這樣作並非萬無一失的,一個特例即是Opera可使用userAgent假裝本身。下面是假裝成IE的userAgent:Mozilla/5.0 (Windows NT 5.1; U; Edition IBIS; zh-cn; rv:1.8.1) Gecko/20061208 Firefox/2.0.0 Opera 9.64;在徹底假裝的狀況下,最後的「Opera 9.64」這個字符串也不會出現,但Opera也有特殊的識別自身的方法,它會自動聲明一個opera全局變量!

不但如此,咱們的檢測還忽略了一點,就是那些使用相同引擎而品牌不一樣的瀏覽器,因此,直接檢測瀏覽器是沒有必要的,檢測瀏覽器的解釋引擎纔是有必要的!

    var Browser = {
        isIE:navigator.userAgent.indexOf("MSIE")>-1 && !window.opera,
        isGecko:navigator.userAgent.indexOf("Gecko")>-1 && !window.opera 
        && navigator.userAgent.indexOf("KHTML") ==-1,
        isKHTML:navigator.userAgent.indexOf("KHTML")>-1,
        isOpera:navigator.userAgent.indexOf("Opera")>-1
    };

 

對象檢測

瀏覽器檢測就到此結束了,下面應該講一下對象檢測!對象檢測實際上是比瀏覽器檢測更加有效更加科學方法,並且咱們以前一直在使用!

    function addEvent(obj,evtype,bubbles) {
        if (obj.addEventListener) {....}
        else if (obj.attachEventListener) {....}
    }

 

對象檢測避免了瀏覽器引擎的多樣性,即當咱們須要某種功能時,咱們直接檢測瀏覽器是否支持該功能,而不用管瀏覽器是什麼牌子的!

何時該使用瀏覽器檢測?何時該使用對象檢測?

答案是能使用對象檢測時總該使用對象檢測,只有當必須對瀏覽器進行識別或沒法使用對象檢測時才進行userAgent判斷

    //一段用於將當前頁面添加到用戶收藏夾的代碼,兩個不一樣的版本
    window.external.addFavorite(location,"收藏頁面");//IE
    window.sidebar.addPanel("收藏頁面",location,"");//火狐
    //因爲在火狐下window也具備external屬性,而且在IE下判斷window.external.addFavorite會出錯
    if (window.external.addFavorite) {...}//代碼在IE下會出錯
    //可使用瀏覽器檢測,避免意外
    if (Browser.isIE) {
        window.external.addFavorite(location,"收藏頁面");//IE
    } else if (Browser.isGecko) {
        window.sidebar.addPanel("收藏頁面",location,"");//火狐及其它相同引擎的瀏覽器
    }

 

當你的腳本和其它腳本一塊兒工做時(尤爲和那些有問題的腳本),有時候須要同時使用對象檢測與瀏覽器檢測

    //對於window.innerWidth這些屬性,可能有些腳本會建立一個兼容多個瀏覽器的同名屬性
    if (isIE) {//它聰明的使用了瀏覽器檢測
        window.onresize = function () {
            window.innerWidth =document.documentElement.clientWidth;
            window.innerHeight = document.documentElement.clientHeight;
        };
        window.onresize();
    }
    //然而咱們的腳本對其進行檢測時就麻煩了
    if (window.innerWidth) {//僅當在FF下時(FF支持position:fixed)才這樣作
        obj.style.position="fixed";
        obj.style.right=window.innerWidth/2+"px";
        obj.style.bottom=window.innerWidth/2+"px";
        ....
    }

 

固然,使用瀏覽器檢測始終是困難重重的,而對於測試文檔是否支持某種特性,使用對象檢測多是最有效的,還有另外一種方法能夠直接測試瀏覽器是否支持某標準!

測試與DOM標準的一致性

document對象有個implementation屬性,該屬性只有一個方法hasFeature(),用來測試瀏覽器是否支持某個DOM標準!

    //測試是否支持XML DOM 1.0
    var supportXML = document.implementation.hasFeature("XML", "1.0");

 

特 徵 支持的版本 描 述
Core 1.0, 2.0, 3.0 基本的DOM,給予了用層次樹來表示文檔的能力
XML 1.0,2.0,3.0 核心的XML擴展,增長了對CDATA Section、處理指令和實體的支持
HTML 1.0,2.0 XML的HTML擴展,增長了對HTML特定元素和實體的支持
Views 2.0 基於特定樣式完成對文檔的格式化
StyleSheets 2.0 爲文檔關聯樣式表
CSS 2.0 支持級聯樣式表1(CSS Level 1)
CSS2 2.0 支持級聯樣式表2(CSS Level 2)
Events 2.0 通用DOM事件
UIEvents 2.0 用戶界面事件
MouseEvents 2.0 由鼠標引發的事件(點擊、鼠標通過,等等)
MutationEvents 2.0 當DOM樹發生改變時引起的事件
HTMLEvents 2.0 HTML 4.01的事件
Range 2.0 操做DOM樹中某個特定範圍的對象和方法
Traversal 2.0 遍歷DOM樹的方法
LS 3.0 在文件和DOM樹之間同步地載入和存儲
LS-Async 3.0 在文件和DOM樹之間異步地載入和存儲
Validation 3.0 用於修改DOM樹以後仍然保持其有效性的方法

儘管這個至關方便,可是,使用implementation.hasFeature()有其明顯的缺陷——決定DOM實現是否對DOM標準的不一樣的部分相一致的,正是去進行實現的人(或公司)。要讓這個方法對於任何值都返回true,那是很簡單的,但這並不必定表示這個DOM實現真的和全部的標準都一致了。目前爲止,最精確的瀏覽器要數Mozilla,但它多少也有一些並不徹底和DOM標準一致的地方,這個方法卻返回爲true。

錯誤處理

無盡的DOM兼容性問題,若是老是使用對象檢測,就會帶來無盡的if else之類的分支語句,並且檢測某些對象的某些屬性時還會引起錯誤(尤爲是在IE下),由於通常的JavaScript對象均可以轉換成布爾值,但瀏覽器內置的一些方法或對象並非JavaScript建立了,它們不必定可以轉換成布爾值!因此,使用錯誤處理語句不但避免了分支判斷,並且能夠很優雅的處理錯誤!

try {} catch(e) {} finally {}

    function addFav(address,name) {
        try {
            window.sidebar.addPanel(name,address,"");//FF方法
            //在try語句中,若是腳本出錯,會自動跳轉到catch語句執行
        } catch(e) {//這裏的e是必須的,是語法的一部分,它表示一個錯誤對象
            window.external.addFavorite(address,name);//IE
            //若是在這裏還出現錯誤,瀏覽器就會將這個錯誤拋出
        }
    }

 

Error對象

JavaScript內置了一個Error構造函數,能夠建立一個錯誤對象,並可使用throw語句手動拋出錯誤!

    var err = new Error();
    throw err;
    //在IE中,會在錯誤窗口中顯示「未指明的錯誤」,而FF中則是空字符串
    //拋出錯誤後,腳本便會中止往下執行
    var message = "我拋出的錯誤!";//錯誤描述
    err = new Error(message);
    throw err;

 

錯誤對象的屬性:message屬性保存與錯誤對象相關的描述文字,number對象保存錯誤代碼。(錯誤號是 32 位的值。高 16 位字是設備代碼,而低字是實際的錯誤代碼,不過錯誤代碼對咱們來講是沒什麼意義的)

        try {
            undefined();//當try語句中腳本出現錯誤時,會自動拋出一個錯誤對象
        } catch(e) {//e是自動建立是局部變量,是Error的實例
            alert("錯誤信息是:"+e.message+"\n"+"錯誤代碼是:"+e.number);
        } finally {
            //finally語句無論出現不出現錯誤,都將執行,通常用於出錯時釋放對象
        }

 

onerror事件處理

DOM還有個onerror事件處理,當頁面載入出錯,圖象載入出錯及頁面腳本出錯時會執行註冊的事件處理函數,一個經常使用的方法即是,在事件處理函數中返回true能夠阻止瀏覽器出現錯誤提示!

    window.onerror = function () {
        alert("出錯時你會看到個人!");
        return true;
    };

 

另一個用法是,能夠監測圖像的載入,若是圖像載入出錯,能夠從新載入圖像(從新設置src屬性),也能夠利用這個方法來測試一下圖像是否存在(好比檢測用戶輸入的遠程圖像的URL是否有效)

儘管使用try {} catch(e) {}語句,及使用onerror事件處理能夠處理腳本運行時錯誤,但它們是不能處理語法錯誤的!另外,使用錯誤處理語句並非爲了隱匿錯誤,而只是爲了避免干擾腳本的繼續執行!

記錄錯誤

處理了這麼多錯誤後,記錄錯誤這樣的事情其實已經作過不少次了,主要有下面幾種方法

  • 使用alert語句,好處是可讓腳本暫停運行,壞處即是彈窗不那麼好控制
  • 使用document.write方法,這種方法天然避免了彈窗無法關閉的狀況,但很差控制腳本運行!另外一點即是,使用document.write會清空當前頁面!
  • 與document.write方法相似的是使用一個自建的控制檯(好比一個DIV),而後將錯誤信息一條一條的添加進去,這種方法確定比document.write好多了!
  • 還有另外一種方法即是使用瀏覽器內置的控制檯,如在JavaScript裏面能夠調用Java控制檯並向其中寫入信息(前提是安裝了JRE)
    java.lang.System.out.println("錯誤信息!");//使用Java控制檯
    console.log("錯誤信息!");//使用火狐的控制檯
    opera.postError("錯誤信息!");//使用Opera的控制檯

 

使用庫提升開發效率

庫,就是一些能夠方便的應用到當前的開發體系中的代碼資源,JavaScript庫又被稱之爲JavaScript框架,它是由一些類和普通函數構成。使用庫,可使開發者沒必要關心程序的實現細節而只專心於業務邏輯。有不少流行的庫,它們大都可以跨瀏覽器工做,而且採用了面向對象的良好編碼方式。 事實上,庫就是將以前咱們寫的那些能夠跨瀏覽器運行的函數集中到一個JS文件中,以便能在全部頁面都可以重複利用這些代碼!固然,它們不是簡簡單單的將函數放到一塊兒!下面是一些流行的庫及其優缺點:

  • Prototype

    不要把它和JavaScript裏面的prototype相混淆,Prototype是一個JS框架(官方稱之爲框架),能夠說是最先也是最出名的JS框架了。 它提供了許多JS面向對象的擴展及DOM操做API,以前它一直因爲缺少API文檔而備受詬病,但如今其文檔已很充足。 它的優勢顯而易見,它只提供一些核心的,底層的功能,因此代碼精簡,體積較小,易學易用,但因爲其只具備底層功能,每每須要協同其它UI庫來運行! 目前,基於Prototype的庫已經有不少,著名的有集成Prototype庫的RoR Ajax庫,以及爲Prototype提供許多視覺特效的Scriptaculous庫。

  • jQuery

    jQuery是一款同Prototype同樣優秀js開發庫,特別是對css和XPath的支持,使咱們寫js變得更加方便!若是你不是個js高手又想寫出優秀的js效果,jQuery能夠幫你達到目的!而且簡潔的語法和高效率一直是jQuery追求的目標。(其官網標語:jQuery將改變您書寫JavaScript的方式!)。 連YAHOO-UI都重用了不少jQuery的函數。支持插件是jQuery的另外一大優勢,能夠無即的擴展其功能。其缺點即是內部結構複雜,代碼較爲晦澀,通常的新手根本沒法看懂其源碼。因此jQuery適合開發而不適合一個剛開始學習建立JS庫的新手研究其源碼。

  • EXT-JS

    EXT-JS前身是YAHOO-UI,EXT-JS是具備CS風格的Web用戶界面組件 能實現複雜的Layout佈局,界面效果能夠和BackBase(另外一JS庫)媲美,並且使用純javascript代碼開發。真正的可編輯的表格Edit Grid,支持XML和Json數據類型,直接能夠遷入grid。許多組件實現了對數據源的支持,例如動態的佈局,可編輯的表格控件,動態加載的Tree 控件、動態拖拽效果等等。1.0 beta版開始同Jquery合做,推出基於jQuery的Ext 1.0,提供了更多有趣的功能。 對於一個喜歡JAVA的開發者來講,EXT-JS相似於java的結構,清晰明瞭,另外一特色其能夠實現華麗的使人震撼的WEB應用程序。固然,缺點也很嚴重,因爲不少HTML及CSS代碼都是EXT-JS自已建立的,因此其界面構造十分複雜,沒有讓咱們本身寫CSS的餘地。

  • Dojo

    Dojo是目前最爲強大的工業級JS框架。它在本身的Wiki上給本身下了一個定義,dojo是一個用JavaScript編寫的開源的DHTML工具箱。dojo很想作一個「大一統」的 工具箱,不只僅是瀏覽器層面的,野心仍是很大的。Dojo包括ajax, browser, event, widget等跨瀏覽器API,包括了JS自己的語言擴展,以及各個方面的工具類庫,和比較完善的UI組件庫,也被普遍 應用在不少項目中,他的UI組件的特色是經過給html標籤增長tag的方式進行擴展,而不是經過寫JS來生成,dojo的API模仿Java類庫的組織 方式。 用dojo寫Web OS可謂很是方便。dojo如今已經4.0了,dojo強大的地方在於界面和特效的封裝,可讓開發者快速構建一些兼容標準的界面。 Dojo幾乎集了成了上面的JS庫的優勢,其功能非同通常的強大,已獲得了IBM和SUN的支持,可是天然的,其體積也十分大,總共有200多KB,另外,其語法也不如jQuery靈活,對JavaScript語言的加強也不如Prototype。

  • Scriptaculous

    Scriptaculous是基於prototype.js框架的JS效果。包含了6個js文件,不一樣的文件對應不一樣的js效果,因此說,若是底層用 prototype的話,作js效果用Scriptaculous那是再合適不過的了。優勢即是基於Prototype,能夠說是Prototype的插件,不一樣的效果用不一樣的JS文件分開存放,固然,依賴於Prototype也是其缺點。

  • moo.fx

    moo.fx是一個超級輕量級的javascript特效庫(3k),可以與prototype.js框架一塊兒使用。它很是快、易於使用、跨瀏覽器、符合標準,提供控制和修改任何HTML元素的CSS屬性,包括顏色。它內置檢查器可以防止用戶經過屢次或瘋狂點擊來破壞效果。moo.fx總體採用模塊化設計,因此能夠在它的基礎上開發你須要的任何特效。輕量是其最大的優勢,固然其缺點即是輕量級的,可是輕量級的JS庫能有如此強大已經很不錯了。

命名空間

在建立庫以前,第一個要考慮的問題即是如何防止變量重名的問題!解決方案即是使用命名空間!命名空間是JAVA等語言中的一個概念,JavaScript並不支持命名空間,但因爲JavaScript的靈活性,咱們可使用對象來模似命名空間!

    var NameSpace={};
    NameSpace.fn1 =function () {};
    NameSpace.fn2 =function () {};

 

如今,fn1與fn2兩個函數就同屬於NameSpace命名空間中了,它們不會也全局中的fn1或fn2衝突,固然,在使用的時候必需加上NameSpace前綴。這樣使用命名空間並非最簡單的,由於咱們不得不在任何地方調用這些函數的時候都加上NameSpace前綴。下面是使用JavaScript閉包來解決的方案:

    var NameSpace={};
    (function () {
        function fn1() {
        }
        function fn2() {
            fn1();//在這裏調用fn1不須要加NameSpace前綴
        }
        NameSpace.fn1=fn1;//將其添加爲全局變量NameSpace的屬性,以便能在函數外訪問
        NameSpace.fn2=fn2;
    })();
相關文章
相關標籤/搜索