Javascript 中 DOM2 比 DOM0 有什么优点?

IE 中,DOM2 不支持 addEventListener 而只能使用 attachEvenListener ,这使用我们需要进行能力判断去做跨浏览器兼容,那么既然这么麻烦,为什么不直接使用 DOM0 的 elem.onclick 呢?DOM2 有什么比 DOM0 好的地方?

阅读 8.5k
2 个回答

感谢 @王子亭 提供的链接,我觉得挺不错,并且翻译成中文,分享给大家!

问题: addEventListener 和 onclick 有什么不同?

问题描述

var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);

代码同时保存在一个分离的 .js 文件里面,而且它们都能完美地运行。

最佳答案

它们都是正确的,它们之间没有哪个是“最好的”,而且开发者有可能同时使用这两个方法。

事件监听器(Event Listeners,包括 addEventListener 以及 IE 的 attacheEvent)

旧版本的 IE 在执行 Javascript 时与几乎所有其它浏览器不同,在 IE 9 之前的版本中,你需要使用 attachEvent 模块,就像这样:

element.attachEvent('onclick', function() { /* do stuff here*/ });

在大部分其它浏览器(包括 IE 9 以及更新的版本)中,你可以使用 addEventListener,就像这样:

element.addEventListener('click', function() { /* do stuff here*/ }, false);

使用这些方法(DOM2 事件),理论上你可以向某个元素加入无数的事件。但实际上,这会受限于客户端的内存容量以及其它的性能问题,而这对于每一个浏览器都是不同的。

上面的例子使用的都是匿名函数,你也可以将一个函数表达式或者一个闭包添加到事件监听器上:

var myFunctionReference = function(){ /* do stuff here */ }

element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFUnctionReference, false);

addEventListener 还有一个特点就是最后的参数,它会控制监听器在事件冒泡阶段时就作出反应。有大约 95% 的可能会像我在例子中那样使用 false。这个参数在 attachEvent 中或在使用内联事件(inline Events) 时没有等效的参数。

内联事件 (Inline Events, 即 HTML 中的 onclick="" 属性 和 element.onclick)

在所有支持 Javascript 的浏览器中,你可以将一个事件监听器内联,也就是像下面的 HTML 代码那样:

<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>

虽然它的确是可以完成任务的,而且简单直接,但绝大部分有经验的开发者都会尽量避开使用这样的方法。同时,你不能在这里使用闭包或者匿名函数(虽然处理程序本身就是一个匿名函数),而且你的控制范围是有限的。

另一个方法是这样的(也就是你提到的):

element.onclick = funtion () { /* do stuff here */ }

实际上这等价于内联 Javascript (也就是上面那种在 HTML 标签属性中添加的方法),不过这样可以拥有更大的控制范围,同时可以使用匿名函数、函数表达式或闭包。

内联事件有个重大的缺点就是,不像上面提到的事件监斩器那样,你只可以指定一个内联事件。内联事件会转化元元素的属性,那意味着当指定多个的内联事件时,它之前所指定的内联事件会被覆盖掉。

使用上面 HTML 代码中的 <a> 标签来举个例子:

var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };

当你点击这个元素后,你可以看到 "Did stuff #2",原因是第二个值覆盖了第一个指定的 onclick 属性,同时,会把 HTML 中 onclick 属性也覆盖掉。点击这里可以试试:http://jsfiddle.net/jpgah/

二者谁更好呢?

主要的问题是浏览器兼容性和必要性。你目前是否需要添加一个以上的事件到一个元素上?未来是否需要?大部分时候,你是需要的。所以,使用 attachEventaddEventListener 是非常有必要的,不然用内联事件就好了。

JQuery 以及很多其它的 Javascript 框架都为不同的浏览器封装了通用的处理 DOM2 事件的通用模型(Models),这样你可以在做跨浏览器兼容时不需要为 IE 的历史遗留问题而烦恼了。同样的代码在 jQuery 中做跨浏览器兼容,只需要这样:

$(element).on('click', function () { /* do stuff */ });

当然了,不要因为这么一件事而使用一个框架。你可以很容易地写出一个小工具来兼容旧版本的浏览器:

function addEvent(element, evnt, funct){
    if (element.attachEvent)
        return element.attachEvent('on' + evnt, funct);
    else
        return elemt.addEventListener(evnt, funct, false);
}

//example
addEvent(
    document.getElementById('myElement'),
    'click',
    function () { aler('hi!'); }
);

点击可以试试:http://jsfiddle.net/bmArj/

综上,除非你看的这段脚本用其他方法处理了不同浏览器之间的差异 ,使用 addEventListener 的部分不会在 IE 9 以下的 IE 工作。

文档及相关阅读

原问题链接:http://stackoverflow.com/questions/6348494/addeventlistener-vs-onclick

DOM Level 2 Event Handler更加flexible。 比如,

  • 绑定多个同一类型的事件。前者不能, 我觉得是前者最大的缺点。

  • 通过第3个parameter控制事件是bubbling还是capture。前者不能。

  • .preventDeault()可以取消default behavior; .stopPropagation() 可以取消事件的传播。而, 前者只能通过return false来同时取消propagation和default behavior。

  • cross-browser。需要花费一点力气写成function,但可以从中学习兼容知识。

  • 不能写在HTML里。

  • Live in the future

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏