JavaScript添加跨浏览器事件的函数实现:使用attachEvent/addEventListener与内联事件。

10
为了添加事件,我们可以使用这个简单的第一解决方案:
function AddEvent(html_element, event_name, event_function) 
{       
   if(html_element.attachEvent) //Internet Explorer
      html_element.attachEvent("on" + event_name, function() {event_function.call(html_element);}); 
   else if(html_element.addEventListener) //Firefox & company
      html_element.addEventListener(event_name, event_function, false); //don't need the 'call' trick because in FF everything already works in the right way          
} 

或者使用这个第二种解决方案(添加内联事件):
function AddEvent(html_element, event_name, event_function) 
{       
   var old_event = html_element['on' + event_name];
   if(typeof old_event !== 'function')
      html_element['on' + event_name] = function() { event_function.call(html_element); };
   else
      html_element['on' + event_name] = function() { old_event(); event_function.call(html_element); };
}

这两种方法都是跨浏览器的,可以按以下方式使用:

AddEvent(document.getElementById('some_div_id'), 'click', function() 
{             
   alert(this.tagName); //shows 'DIV'
});  

我有一种感觉,attachEvent/addEventListener 在事件处理实现中使用更多,所以我想知道:

使用第二种方法有什么缺点/劣势,我最好知道吗?

我能看到两个,但我对更多的感兴趣(如果有的话):

  1. 第二个解决方案通过添加内联事件来破坏元素的innerHTML
  2. 使用第二个解决方案,我可以轻松地删除与特定事件类型相关联的所有函数(html_element['on' + event_name] = null),但我无法使用detachEvent/removeEventListener来精确删除特定的函数。

任何像"使用jQuery"或其他框架的回答都是无意义的!


你忘记了 event 参数。 - Bergi
@Bergi:在哪里,什么? - Marco Demaio
在所有这些 event_function.call(…) 表达式中,处理程序被调用时没有传入 event - Bergi
谢谢,但我认为将事件传递给event_function并不是必须的。我同意您的观点,如果事件处理程序想要对事件进行操作,则需要使用事件参数。 - Marco Demaio
你的意思是什么,“这不是强制性的”?我以为你想写一个通用的addeventlistener函数。你无法知道处理程序是否使用事件对象。 - Bergi
@Bergi:就像我说的,你是正确的!我只是想说,即使你不传递事件,函数也不会出错!除此之外,在处理程序中从未使用过事件对象这个事实。这里的问题更多地是关于哪种方式可能是最好的,而不是实现一个完整功能的跨浏览器事件监听器。无论如何,我很感激您的评论,请随意编辑我的问题并修复代码,如果您愿意。 - Marco Demaio
2个回答

7
使用第二种解决方案需要手动调用先前的函数,这使得删除特定侦听器变得困难(对我来说,这似乎比清除所有侦听器更重要),而第一种解决方案只能同时清除它们,除非您想模拟第一个功能。
个人而言,我总是使用第一种解决方案,因为它具有不必担心清除可能存在的其他事件侦听器的优点。 Mozilla Wiki还列出了第一种解决方案的优点,它适用于任何DOM元素,而不仅仅是HTML元素,并且它允许使用第三个参数在激活侦听器的阶段上进行更精细的控制(捕获或冒泡)。

我认为你在前两段文字中把第一件事和第二件事颠倒了。 - Roatin Marth
+1 我看了你建议的链接,但是 Mozilla 网站解释的三个点并不完全正确:“1. 它允许为一个事件添加多个处理程序”这是真的,但是使用我在答案中编写的两个函数,您也可以添加多个事件处理程序。“2. 它使您对侦听器激活时的阶段(捕获 vs 冒泡)有更精细的控制”这是真的,但是很容易添加 stopEvent 函数来防止默认和停止冒泡,此外,attachEvent 没有这样的行为,因此仍然需要创建跨浏览器函数。 - Marco Demaio
"3. 它适用于任何DOM元素,而不仅仅是HTML元素。" 这很有趣,但我没有看到一个真实的例子,我需要向一个不是HTML元素的DOM节点添加事件。 - Marco Demaio
  1. 没错,但是你的函数是非本地的,任何想要注册事件的其他人都会清除整个onload。
  2. 对的。
  3. SVG标签?
- yorick

3
我会这样使用两个代码:
function addEvent(html_element, event_name, event_function) {
    if (html_element.addEventListener) { // Modern
        html_element.addEventListener(event_name, event_function, false);
    } else if (html_element.attachEvent) { // Internet Explorer
        html_element.attachEvent("on" + event_name, event_function);
    } else { // others
        html_element["on" + event_name] = event_function;
    }
};

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接