市场上的浏览器种类多的不可胜数,它们的解释引擎各不相同,期待全部浏览器都一致的支持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; })();