市場上的瀏覽器種類多的不可勝數,它們的解釋引擎各不相同,期待全部瀏覽器都一致的支持JavaScript,CSS,DOM,那要等到不知何時,然而開發者不能幹等着那天。歷史上已經有很多方法來解決瀏覽器兼容問題了,主要分爲兩種:1.userAgent字符串檢測,2.對象檢測;固然,也不能考慮全部的瀏覽器,咱們須要按照客戶需求來,若是能夠確信瀏覽網站的用戶都使用或大部分使用IE瀏覽器,那麼你大可放心的使用IE專有的那些豐富的擴展,固然,一旦用戶開始轉向另外一個瀏覽,那麼痛苦的日子便開始了。下面是市場上的主流瀏覽器列表:javascript
注意,瀏覽器老是不斷更新,咱們不但要爲多種瀏覽器做兼容處理,還要對同一瀏覽器多個版本做兼容處理。好比IE瀏覽器,其6.0版本和7.0版本都很流行,由於微軟IE隨着操做系統綁定安裝(以前也是同步發行,微軟平均每兩年推出一款我的桌面,一樣IE也每兩年更新一次;直到如今,因爲火狐的流行,IE工做組才加快IE的更新),因此更新的較慢,6.0版和7.0版有很大差異。css
市場上還存在一些其它瀏覽器,但因爲它們都是使用的上面所列瀏覽器的核心,或與上面瀏覽器使用了相同的解釋引擎,因此無需多做考慮。下面是主流的瀏覽器解釋引擎列表:html
Trident (又稱爲MSHTML),是微軟的窗口操做系統(Windows)搭載的網頁瀏覽器—Internet Explorer的排版引擎的名稱,它的第一個版本隨着1997年10月Internet Explorer第四版釋出,以後不斷的加入新的技術並隨着新版本的Internet Explorer釋出。在將來最新的Internet Explorer第七版中,微軟將對Trident排版引擎作了的重大的變更,除了加入新的技術以外,並增長對網頁標準的支持。儘管這些變更已經在至關大的程度上落後了其它的排版引擎。使用該引擎的主要瀏覽器:IE,TheWorld,MiniIE,Maxthon,騰訊TT瀏覽器。事實上,這些瀏覽器是直接使用了IE核心,由於其userAgent字符串中返回的信息與IE是如出一轍的!java
壁虎,英文爲"Gecko"。Gecko是由Mozilla基金會開發的佈局引擎的名字。它本來叫做NGLayout。Gecko的做用是讀取諸如HTML、CSS、XUL和JavaScript等的網頁內容,並呈現到用戶屏幕或打印出來。Gecko已經被許多應用程序所使用,包括若干瀏覽器,例如Firefox、Mozilla Suite、Camino,Seamonkey等等ajax
Presto是一個由Opera Software開發的瀏覽器排版引擎,供Opera 7.0及以上使用。Presto取代了舊版Opera 4至6版本使用的Elektra排版引擎,包括加入動態功能,例如網頁或其部分可隨着DOM及Script語法的事件而從新排版。Presto在推出後不斷有更新版本推出,使很多錯誤得以修正,以及閱讀Javascript效能得以最佳化,併成爲速度最快的引擎。編程
是HTML網頁排版引擎之一,由KDE所開發。KDE系統自KDE2版起,在檔案及網頁瀏覽器使用了KHTML引擎。該引擎以C++編程語言所寫,並以LGPL受權,支援大多數網頁瀏覽標準。因爲微軟的Internet Explorer的佔有率至關高,很多以FrontPage製做的網頁均包含只有IE才能讀取的非標準語法,爲了使KHTML引擎可呈現的網頁達到最多,部分IE專屬的語法也一併支援。目前使用KHTML的瀏覽器有Safari和Google Chrome。而KHTML也產生了許多衍生品,如:WebKit,WebCore引擎瀏覽器
下面是各大瀏覽器使用彈窗顯示的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"; .... }
固然,使用瀏覽器檢測始終是困難重重的,而對於測試文檔是否支持某種特性,使用對象檢測多是最有效的,還有另外一種方法能夠直接測試瀏覽器是否支持某標準!
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建立了,它們不必定可以轉換成布爾值!因此,使用錯誤處理語句不但避免了分支判斷,並且能夠很優雅的處理錯誤!
function addFav(address,name) { try { window.sidebar.addPanel(name,address,"");//FF方法 //在try語句中,若是腳本出錯,會自動跳轉到catch語句執行 } catch(e) {//這裏的e是必須的,是語法的一部分,它表示一個錯誤對象 window.external.addFavorite(address,name);//IE //若是在這裏還出現錯誤,瀏覽器就會將這個錯誤拋出 } }
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語句無論出現不出現錯誤,都將執行,通常用於出錯時釋放對象 }
DOM還有個onerror事件處理,當頁面載入出錯,圖象載入出錯及頁面腳本出錯時會執行註冊的事件處理函數,一個經常使用的方法即是,在事件處理函數中返回true能夠阻止瀏覽器出現錯誤提示!
window.onerror = function () { alert("出錯時你會看到個人!"); return true; };
另一個用法是,能夠監測圖像的載入,若是圖像載入出錯,能夠從新載入圖像(從新設置src屬性),也能夠利用這個方法來測試一下圖像是否存在(好比檢測用戶輸入的遠程圖像的URL是否有效)
儘管使用try {} catch(e) {}語句,及使用onerror事件處理能夠處理腳本運行時錯誤,但它們是不能處理語法錯誤的!另外,使用錯誤處理語句並非爲了隱匿錯誤,而只是爲了避免干擾腳本的繼續執行!
處理了這麼多錯誤後,記錄錯誤這樣的事情其實已經作過不少次了,主要有下面幾種方法
java.lang.System.out.println("錯誤信息!");//使用Java控制檯 console.log("錯誤信息!");//使用火狐的控制檯 opera.postError("錯誤信息!");//使用Opera的控制檯
庫,就是一些能夠方便的應用到當前的開發體系中的代碼資源,JavaScript庫又被稱之爲JavaScript框架,它是由一些類和普通函數構成。使用庫,可使開發者沒必要關心程序的實現細節而只專心於業務邏輯。有不少流行的庫,它們大都可以跨瀏覽器工做,而且採用了面向對象的良好編碼方式。 事實上,庫就是將以前咱們寫的那些能夠跨瀏覽器運行的函數集中到一個JS文件中,以便能在全部頁面都可以重複利用這些代碼!固然,它們不是簡簡單單的將函數放到一塊兒!下面是一些流行的庫及其優缺點:
不要把它和JavaScript裏面的prototype相混淆,Prototype是一個JS框架(官方稱之爲框架),能夠說是最先也是最出名的JS框架了。 它提供了許多JS面向對象的擴展及DOM操做API,以前它一直因爲缺少API文檔而備受詬病,但如今其文檔已很充足。 它的優勢顯而易見,它只提供一些核心的,底層的功能,因此代碼精簡,體積較小,易學易用,但因爲其只具備底層功能,每每須要協同其它UI庫來運行! 目前,基於Prototype的庫已經有不少,著名的有集成Prototype庫的RoR Ajax庫,以及爲Prototype提供許多視覺特效的Scriptaculous庫。
jQuery是一款同Prototype同樣優秀js開發庫,特別是對css和XPath的支持,使咱們寫js變得更加方便!若是你不是個js高手又想寫出優秀的js效果,jQuery能夠幫你達到目的!而且簡潔的語法和高效率一直是jQuery追求的目標。(其官網標語:jQuery將改變您書寫JavaScript的方式!)。 連YAHOO-UI都重用了不少jQuery的函數。支持插件是jQuery的另外一大優勢,能夠無即的擴展其功能。其缺點即是內部結構複雜,代碼較爲晦澀,通常的新手根本沒法看懂其源碼。因此jQuery適合開發而不適合一個剛開始學習建立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是目前最爲強大的工業級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是基於prototype.js框架的JS效果。包含了6個js文件,不一樣的文件對應不一樣的js效果,因此說,若是底層用 prototype的話,作js效果用Scriptaculous那是再合適不過的了。優勢即是基於Prototype,能夠說是Prototype的插件,不一樣的效果用不一樣的JS文件分開存放,固然,依賴於Prototype也是其缺點。
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; })();