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;
    })();
相关文章
相关标签/搜索