addEventListener 与 attachEvent 的区别

对比两种事件监听方法的语法、兼容性和行为差异

问题

addEventListener()attachEvent() 有什么区别?如何编写兼容的事件绑定函数?

解答

基本语法对比

// addEventListener - W3C 标准方法
element.addEventListener('click', handler, false);

// attachEvent - IE8 及以下专有方法(已废弃)
element.attachEvent('onclick', handler);

主要区别

特性addEventListenerattachEvent
标准W3C 标准IE 专有
事件名不带 on 前缀需要 on 前缀
this 指向绑定的元素window
事件流支持捕获和冒泡只支持冒泡
执行顺序按添加顺序顺序不确定

代码示例

const btn = document.getElementById('btn');

// addEventListener 中 this 指向元素
btn.addEventListener('click', function(e) {
  console.log(this);        // <button id="btn">
  console.log(e.target);    // <button id="btn">
  console.log(e.type);      // 'click'
}, false);

// attachEvent 中 this 指向 window(IE8 及以下)
// btn.attachEvent('onclick', function(e) {
//   console.log(this);     // window
//   console.log(e.srcElement); // IE 用 srcElement 代替 target
// });

兼容性封装

// 添加事件
function addEvent(element, type, handler) {
  if (element.addEventListener) {
    // 标准方法
    element.addEventListener(type, handler, false);
  } else if (element.attachEvent) {
    // IE8 及以下
    element.attachEvent('on' + type, handler);
  } else {
    // 降级处理
    element['on' + type] = handler;
  }
}

// 移除事件
function removeEvent(element, type, handler) {
  if (element.removeEventListener) {
    element.removeEventListener(type, handler, false);
  } else if (element.detachEvent) {
    element.detachEvent('on' + type, handler);
  } else {
    element['on' + type] = null;
  }
}

// 使用示例
const btn = document.getElementById('btn');

function handleClick(e) {
  // 兼容获取事件对象
  e = e || window.event;
  // 兼容获取目标元素
  const target = e.target || e.srcElement;
  console.log('clicked:', target);
}

addEvent(btn, 'click', handleClick);

修正 attachEvent 的 this 指向

function addEventFixed(element, type, handler) {
  if (element.addEventListener) {
    element.addEventListener(type, handler, false);
  } else if (element.attachEvent) {
    // 用 call 修正 this 指向
    element.attachEvent('on' + type, function(e) {
      handler.call(element, e || window.event);
    });
  }
}

关键点

  • addEventListener 是标准方法,attachEvent 是 IE8 及以下专有方法,现已废弃
  • 事件名不同:click vs onclick
  • addEventListener 的 this 指向元素,attachEvent 的 this 指向 window
  • addEventListener 第三个参数控制捕获/冒泡,attachEvent 只支持冒泡
  • 现代开发无需考虑 attachEvent,IE8 已被淘汰