首页 » JavaScript » addEventListener、removeEventListener、attachEvent、detachEvent

addEventListener、removeEventListener、attachEvent、detachEvent

事件就是用户或浏览器自身执行的某种动作。诸如click、load和mouseover,都是事件的名字。而响应某个事件的函数就叫做事件处理程序(或事件侦听器)。事件处理程序的名字以“on”开头,因此click事件处理程序就是onclick,load事件的事件处理程序就是onload。为事件指定处理程序的方式有好几种。

DOM0级事件处理程序

通过JavaScript指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。这种为事件处理程序赋值的方法是第四代Web浏览器中出现的,而且至今仍然为所有现代浏览器所支持。原因一是简单,而是具有跨浏览器的优势。要使用JavaScript指定事件处理程序,首先必须取得一个要操作的对象的引用。

每个元素(包括window和document)都有自己的事件处理程序属性,这些属性通常全部小写,例如onclick。将这种属性的只设置为一个函数,就可以指定事件处理程序,如下所示:

var btn = document.getElementById("myBtn");
btn.onclick = function () {
    alert("Clicked");
};

在此,我们通过文档对象取得了一个按钮的引用,然后为它指定了onclick事件处理程序。但要注意,在这些代码运行之前不会指定事件处理程序,因此如果这些代码在页面中位于按钮后面,就有可能在一段时间内怎么单击都没有反映。

使用DOM0级方法指定的事件处理程序被认为是元素的方法。因此,这时候的事件处理程序是在元素的作用域中运行;换句话说,程序中的this引用当前元素。来看一个例子:

var btn = document.getElementById("myBtn");
btn.onclick = function () {
    alert(this.id);  //"myBtn"
};

单击按钮显示的是元素的ID,这个ID是通过this.id取得的。不仅仅是ID,实际上可以在事件处理程序中通过this访问元素的任何属性和方法。以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。

也可以删除通过DOM0级方法指定的事件处理程序,只要像下面这样将事件处理程序属性的值设置为null即可:

btn.onclick = null;  //删除事件处理程序

将事件处理程序设置为null之后,在单击按钮将不会有任何动作发生。

DOM2级事件处理程序

addEventListener()与removeEventListener()用于处理指定和删除事件处理程序操作。所有的DOM节点中都包含这两种方法,并且它们都接受3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值。最后这个布尔值参数是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。

要在按钮上为click事件添加事件处理程序,可以使用下列代码:

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function () {
    alert(this.id);
}, false);

使用DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。来看下面的例子:

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function () {
    alert(this.id);
}, false);
btn.addEventListener("click", function () {
    alert("Hello World");
}, false);

通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。这也意味着通过addEventListener()添加的匿名函数无法移除,如下面的例子所示:

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function () {
    alert(this.id);
}, false);
btn.removeEventListener("click", function () {  //无效!
    alert(this.id);
}, false);

在这个例子中,我使用addEventListener()添加一个事件处理程序。虽然调用removeEventListener()时看似使用了相同的参数,但实际上,第二个参数与传入addEventListener()中的那一个完全不同的函数。而传入removeEventListener()中的事件处理程序函数必须与传入addEventListener()中的相同,如下面的例子所示:

var btn = document.getElementById("myBtn");
var handler = function () {
        alert(this.id);
    };
btn.addEventListener("click", handler, false);
btn.removeEventListener("click", handler, false);  //有效!

重写后的这个例子没有问题,是因为在addEventListener()和removeEventListener()中用来相同的函数。

大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在是时间到达目标之前截获它的时候将事件处理程序添加到捕获阶段。如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序。

IE9、Firefox、Safari、Chrome和Oprea支持DOM2级事件处理程序。

IE事件处理程序

IE中实现了与DOM中用于处理指定和删除事件处理程序操作类似的两个方法:attachEvent()和detachEvent()。这两个方法接受相同的两个参数:事件处理程序名称与事件处理程序函数。由于IE只支持事件冒泡,所以同各个attachEvent()添加的事件处理程序都会被添加到冒泡阶段。

要使用attachEvent()为按钮添加一个事件处理程序,可以使用以下代码:

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function () {
    alert("Clicked")
});

注意,attachEvent()第一个参数是“onclick”,而非DOM的addEventListener()方法中的“Click”。

在IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的作用域。在使用DOM0级方法的情况下,事件处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。来看下面的例子:

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function () {
    alert(this == window);  //ture
})

在编写跨浏览器的代码时,牢记这一区别非常重要。

与addEventListener()类似,attachEvent()方法可以用来为一个元素添加多个事件处理程序。来看下面的例子:

var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function () {
    alert("Clicked");
});
btn.attachEvent("onclick", function () {
    alert("Hello World!")
});

使用attachEvent()添加事件可以通过detachEvent()来移除,条件是必须提供相同的参数。与DOM方法一样,这也意味着添加的匿名函数将不能被移除。不过,只要能够将相对相同函数的引用传给detachEvent(),就可以移除相应的事件处理程序。例如:

var btn = document.getElementById("myBtn");
var handler = function () {
        alert("Clicked");
    }
btn.attachEvent("onclick", handler);
btn.detachEvent("onclick", handler);

这个例子将保存在变量handler中的函数作为事件处理程序。因此,后面的detachEvent()可以使用相同的函数来移除事件处理程序。

支持IE事件处理程序的浏览器有IE和Opera。

跨浏览器的事件处理程序

为了跨浏览器的方式处理事件,不少开发人员会使用能够隔离浏览器差异的JavaScript库,还有一些开发人员会自己开发最合适的事件处理的方法。要保证处理事件的代码能在大多数浏览器下一致的运行,只需关注冒泡阶段。

var EventUtil = {
    addHandler: function (element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    removeHandler: function (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;
        }
    }
};
var btn = document.getElementById("myBtn");
var handler = function () {
        alert("Clicked");
    };
EventUtil.addHandler(btn, "click", handler);
EventUtil.removeHandler(btn, "click", handler);

这两个方法首先都会检测传入的元素中是否存在DOM2级方法。如果存在DOM2级方法,则使用该方法:传入事件类型、事件处理程序函数和第三个参数false(表示冒泡阶段)。如果存在的是IE的方法,则采取第二种方案。注意此时的事件类型必须加上“on”前缀。最后一种可能是使用DOM0级方法。此时,我们使用的是方括号语法来将属性名指定为事件处理程序,或者将属性设置为null。

此文章发表在 JavaScript 标签为 . 将固定链接加入收藏.