Javascript浏览器兼容性

JS <noscript>标签

早期浏览器都面临一个特殊的问题,即当浏览器不支持JavaScript 时如何让页面平稳地退化。对这个问题的最终解决方案就是创造一个<noscript>元素,用以在不支持JavaScript 的浏览器中显示替代的内容。这个元素可以包含能够出现在文档<body>中的任何HTML 元素一一<script>元素除外。

包含在<noscript>元素中的内容只有在下列情况下才会显示出来:
  • 浏览器不支持脚本;
  • 浏览器支持脚本,但脚本被禁用。

符合上述任何一个条件,浏览器都会显示<noscript>中的内容。而在除此之外的其他情况下,浏览器不会呈现<noscript> 中的内容。

请着下面这个简单的例子:
<html>
<head>
<tit1e>Exarnp1e HTML Page</tit1e>
<script type="text/javascript" defer="defer" src="example1. js">< /script>
<script type="text/javascript" defer="defer" src="example2. js">< /script>
</head>
<body>
<noscript><p>本页面需要浏览器支持(启用)JavaScript。</noscript>
</body>
</html>

这个页面会在脚本无效的情况下向用户显示一条消息,而在启用了脚本的浏览器中,用户永远也不会看到它一一尽管它是页面的一部分。

注意:现代浏览器都对JavaScript进行了支持,一般是在用户的浏览器禁用了脚本的情况下才会显示<noscript>的内容。

不推荐使用的嵌入JS脚本的语法

在最早引入<script>元素的时候,该元素与传统HTML的解析规则是有冲突的。由于要对这个元素应用特殊的解析规则,因此在那些不支持JavaScript 的浏览器一一最典型的是Mosaic-一一中就会导致问题。具体来说,不支持JavaScript的浏览帮会把<script>元素的内容直接输出到页面中,因而会破坏页面的布局和外观。

<script><!--function sayHi(){alert ("Hi! " ) ;--></script>


Netscape与Mosaic协商并提出了一个解决方案,让不支持<script>元素的浏览器能够隐藏嵌入的JavaScript 代码。这个方案就是把JavaScript 代码包含在一个HTML 注释中, 像下面这样:
给脚本加上HTML注释后, Mosaic 等浏览器就会忽略<script>标签中的内容,而那些支持JavaScript 的浏览器在遇到这种情况时,则必须进一步确认其中是否包含需要解析的JavaScript 代码。

虽然这种注释JavaScript 代码的格式得到了所有浏览器的认可,也能被正确解释,但由于所有的现代浏览器都已经支持JavaScript ,因此也就没有必要再使用这种格式了。

JS事件(Event)兼容性探究

 

事件(Event)即为用户的动作,例如:用户点击鼠标,产生onclick事件;按下键盘,产生onkeyDown事件;改变输入框的值,产生onchange事件...

W3C标准规定,事件是作为函数的参数传入的,例如:
<p id="demo">点击我将获得屏幕坐标</p>
document.getElementById("demo").οnclick=function(e)
{
    alert(e.screenX);
}
当在元素上点击时,弹出警告框,内容为鼠标在屏幕上的横坐标。这里函数传入的参数e,就是事件,浏览器会实时跟踪用户的行为,如e.screenX、e.screenY、e.offsetX、e.offsetY...

这种做法在FireFox、Chrome、Safari等遵循W3C规范的浏览器下是没有问题的,唯独在IE(暂时仅限于8.0以下版本,8.0以上版本笔者未曾测试)下是行不通的,IE采用了一种非标准的方式,并不是将事件作为函数参数传入,而是将事件作为window对象的event属性:window.event、window.event.screenX...

所以,我们在写代码的时候要照顾到IE,做好事件的兼容。

下面是笔者给出的一个简单的兼容示例,该示例并没有去判断浏览器,仅仅使用了一个小技巧。
<p id="demo">点击我将获得屏幕坐标</p>
document.getElementById("demo").οnclick=function(e)
{
    var e=e||event;
    alert(e.screenX);
}
注意,不要将var e=e||event; 写成 var e=event||e; ,这在FireFox下会提示错误,FireFox无法处理未声明未赋值的变量event。

这里大家可能有疑虑,为什么是var e=e||event; ,为什么是 或运算(||),这样的结果只能是e=true或者e=false?

笔者告诉大家,在大多数编程语言里,或运算(||)返回的并不只是true或者false,而是返回第一个不为false的变量的值, 例如:
var a=5||6;  //a=5
var b=0||5;  //b=5
var c=false||"www.itxueyuan.com";  //c="www.itxueyuan.com"
var e=e||event;  //e为用户事件

好,这几个例子,笔者相信大家一定明白了,上面对事件兼容的巧妙处理,也就迎刃而解了。

IT学院提醒,大家在处理浏览器兼容问题的时候,尽量不要去判断浏览器,那将会为向后兼容带来风险,或许某个升级的版本开始遵循W3C标准,我们之前写的代码在该版本上就会产生错误,得不到预想结果。

例如,某个升级的IE版本支持将事件作为函数参数传入,抛弃了将事件作为window的属性,而我们的代码,恰恰是这个样子的:
if( (/ie/i).test(navigator.userAgent) )
    document.getElementById("demo").οnclick=function()
    {

Javascript addEventListener和attachEvent的区别


        alert(window.event.screenX);
    }
else
    document.getElementById("demo").οnclick=function(e)
    {
        alert(e.screenX);
    }
那么在升级的IE浏览器上运行就会产生错误了。

最后,梳理了思路,再把上面的代码重复一遍。
<p id="demo">点击我将获得屏幕坐标</p>
document.getElementById("demo").οnclick=function(e)
{
    var e=e||event;
    alert(e.screenX);
}

浏览器内核

要搞清楚浏览器内核是什么,首先应该先搞清楚浏览器的构成。简单来说浏览器可以分为 两部分,shell+内核。其中shell的种类相对比较多,内核则比较少。Shell是指浏览器的外壳:例如菜单,工具栏等。主要是提供给用户界面操 作,参数设臵等等。它是调用内核来实现各种功能的。内核才是浏览器的核心。内核是基于标记语言显示内容的程序或模块。也有一些浏览器并不区分外壳和内核。 从Mozilla将Gecko独立出来后,才有了外壳和内核的明确划分。目前主流的浏览器有IE6/7/8、Mozilla、FireFox、Opera、Safari、Chrome、Netscape等。

什么是浏览器内核

浏览器内核又可以分成两部分:渲染引擎(layout engineer或者Rendering Engine)和JS引擎。它负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至 显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。JS引擎则是解析Javascript语言,执行javascript语言来实现网页的动态效果。最开始渲染引 擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。有一个网页标准计划小组制作了一个ACID来测试引擎的兼容性和性能。内核的种类很多,如加上没什么人使用的非商业的免费内核,可能会有10多种,但是常见的浏览器内核可以分这四种:Trident、Gecko、 Presto、Webkit。


 

渲染引擎

Trident又称MSHTML,是微软开发的渲染引擎(包含了Javascript引擎JScript),目前很多浏览器都使用这个引擎,例如IE,MaxThon,TT,The World,360,搜狗浏览器,Maxthon(最新版已经不使用)等。 Gecko是C++开发的,Open Source的渲染引擎,包括了SpiderMonkey(Rhino)。主要的使用者有Firefox,Netscape6及以上版本,MozillaSuite/SeaMonkey等 。
Webkit是苹果公司基于KHTML开发的。他包括Webcore和JavaScriptCore(SquirrelFish,V8)两个引擎。主要的使用者有Safari,Chrome。 Presto由Opera Software公司开始的,用于Opera的渲染引擎。Macromedia Dreamweaver (MX版本及以上)和Adobe Creative Suite 2也使用了Presto的内核。主要的使用者为Opera7及以上。

JS引擎

JavaScript最初由网景公司的Brendan Eich设计,是一种动态、弱类型、基于原型的语言,内臵支持类。以它为基础,制定了ECMAScript标准。他的起源并不是如《Javascript高级程序设计》书中所述,是Brendan Eich自主发明的。(参考aimingoo的考证文章)JavaScript在浏览器的实现中还必须含有DOM和BOM。Web浏览器一般使用公共API来创建主机对象来负责将DOM对象反射进JavaScript。

 

Javascript对鼠标滚轮事件的处理

 W3C并没有对鼠标滚轮事件进行规范,各浏览器厂商封装了不同的实现方法,事件属性也不一样,号称最标准的FireFox,用了一个私有实现DOMMouseScroll。不过,其他浏览器都是用onmousewheel实现,所以做兼容处理的难度也不大。

浏览器 实现方法 事件属性 向上滚动 向下滚动
FireFox DOMMouseScroll detail -3 3
非FireFox onmousewheel wheelDelta 120 -120

所谓事件属性,就是滚轮滚动时某个特定变量的变化。该变量不需要用户定义,是作为事件的属性出现的。

  • 对于FireFox,这个变量是detail:滚轮向上滚动,detail=-3;向下滚动,detail=3。
  • 对于非FireFox,这个变量是wheelDelta:滚轮向上滚动,wheelDelta=120;向下滚动,wheelDelta=-120。


另外,还有一点需要注意。

  • 在FireFox下,DOMMouseScroll必须通过addEventListener来绑定,如:
        element.addEventListener("DOMMouseScroll",fun,false)
  • 在非FireFox下,就没有限制了,除了上述方法,还可用下边的代码:
        element.onmousewheel=function(){}


笔者最后总结了一段兼容代码,给大家使用。

  • 对于实现方法的兼容:
    /**
    * 注册滚轮事件函数
    * @param ele  注册的事件对象
    * @param fun  注册事件函数
    */ 
    function mouseWheel(ele,fun)
    {
        (/firefox/i).test(navigator.userAgent)?ele.addEventListener("DOMMouseScroll",fun,false):ele.onmousewheel=fun;
    }
  • 对于事件属性的兼容:
    /**
    *  对滚轮事件属性的兼容处理,不管何种浏览器,最后统一为:鼠标轮向上滚动detail=-3,向下滚动detail=3
    */ 
    function fun(e)
    {
        var e=e||event;
        var detail=e.detail||parseInt(-e.wheelDelta/40);
        /* 添加代码 */
    }

实例:鼠标在图片上滚动,图片放大或缩小。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>效果:鼠标在图片上滚动,图片放大或缩小</title>
</head>
<body>
<img src="/uploads/allimg/121023/1-1210231013513W.jpg" />
<br /><br /><br /><br />
<img src="/uploads/allimg/121023/1-12102321502QO.png" />
<script language="JavaScript" type="text/javascript">
function fun(e)
{
    var e=e||event;
    var detail=e.detail||parseInt(-e.wheelDelta/40);
this.setAttribute("height",this.offsetHeight+4*detail);
}

function mouseWheel(ele,fun)
{
    (/firefox/i).test(navigator.userAgent)?ele.addEventListener("DOMMouseScroll",fun,false):ele.onmousewheel=fun;
}

for(var imgs=document.getElementsByTagName("img"),len=imgs.length,i=0;i<len;i++)
{
mouseWheel(imgs[i],fun)
}
</script>
</body>
</html>
 

Javascript addEventListener和attachEvent的区别

首先,Javascript有3种绑定事件监听的方法:

  1. <div οnclick="alert("事件绑定成功了!")">事件绑定Demo</div>
  2. <div id="div1">事件绑定Demo</div>
    document.getElementById("div1").οnclick=function(){
        alert("事件绑定成功了!");
    }
  3. <div id="div1">事件绑定Demo</div>
    function  fun(){
        alert("事件绑定成功了!");
    }
    document.getElementById("div1").addEventListener("click",fun,false);

addEventListener和attachEvent都是第三种绑定事件监听的方法,区别如下。

一、addEventListener和attachEvent的兼容性问题

  • addEventListener是符合W3C规范的事件绑定方法,FireFox、Chrome、Safari都是用它来绑定事件。
  • attachEvent是IE私有的,不符合W3C规范,而且在IE下,只能使用它来绑定事件,addEventListener是无效的。

所以,要想绑定事件,必须处理兼容性问题。

二、addEventListener和attachEvent的语法规则

  • addEventListener共有3个参数,如下所示:
    element.addEventListener(type,listener,useCapture);
    参数 参数说明
    element 要绑定事件的对象,及HTML节点。
    type 事件名称,注意去掉事件前边的“on”,比如“onclick”要写成“click”,“onmouseover”要写成“mouseover”。
    listener 要绑定的事件监听函数,注意只写函数名,不要带括号。
    userCapture 事件监听方式,只能是true和false:true,采用capture(捕获)模式;false,采用bubbling(冒泡)模式。如无特殊要求,一般是false。
    这里有必要说一下捕获模式和冒泡模式的区别。

    如图所示,有两层div元素,而且都设定有click事件,一般来说,如果我在内层蓝色的元素上click不只会触发蓝色元素的click事件,还会同时触发红色元素的click事件,而useCapture这个参数就是在控制这时候两个click事件的先后顺序。如果是false,那就会使用bubbling(冒泡)模式,他是从内而外的流程,所以会先执行蓝色元素的click事件再执行红色元素的click事件,如果是true,那就是capture(捕获)模式,和bubbling(冒泡)模式相反是由外而内,会先执行红色元素的click事件才执行蓝色元素的click事件。
    如果不同层的元素使用的useCapture不同,会先从最外层元素往目标元素寻找设定为capture(捕获)模式的事件,到达目标元素执行目标元素的事件后,再寻原路往外寻找设定为bubbling(冒泡)模式的事件。
  • attachEvent共有2个参数,如下所示:
    element.attachEvent(type,listener);
    参数 参数说明
    element 要绑定事件的对象,及HTML节点。
    type 事件名称,注意加上事件前边的“on”,比如“onclick”和“onmouseover”,这是与addEventListener的区别。
    listener 要绑定的事件监听函数,注意只写函数名,不要带括号。

三、代码兼容处理

function regEvent(ele, event_name, fun)
{
    if (window.attachEvent) 
        ele.attachEvent(event_name, fun);  //IE浏览器
    else
    {
        event_name = event_name.replace(/^on/, “”);   //如果on开头,删除on,如onclick->click
        ele.addEventListener(event_name, fun, false);  //非IE浏览器
    }
}

注意,请不要以这种方式来判断IE浏览器:
    (/msie/i).test(navigator.userAgent)
此种方法虽然简单易懂,但是有一个很大的隐患,就是浏览器升级以后支持W3C标准了,而并没有做向后兼容,这种情况下就会出现错误提示,程序崩溃,增加了维护成本。

 

转载于:https://my.oschina.net/u/242764/blog/483053

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值