JS 13.2 事件处理程序

13.2 事件处理程序

事件就是用户或浏览器自身执行的某种动作;

响应某个事件的函数就叫做事件处理程序(或事件侦听器);

为事件指定处理程序的方式有好几种;

HTML事件处理程序

就是在页面里写响应事件;

<input type="button" value="Click Me" onclick="alert('Clicked')" />
// 双引号
<input type="button" value="Click Me" onclick="alert(&quot;Clicked&quot;)" />
// 函数
<script type="text/javascript">
function showMessage(){
alert("Hello world!");
}
</script>
<input type="button" value="Click Me" onclick="showMessage()" />

好处:

1.拥有一个局部变量event事件对象;

2.this指代目标元素;

缺点:

1.时差:

元素刚一出现的时候用户就有可能去触发事件,这时有可能尚未具备执行条件;

2.这样扩展事件处理程序的作用域链在不同浏览器中会导致不同结果;

不同JavaScript引擎遵循的标识符解析规则略有差异,很可能会在访问非限定对象成员时出错;

这一点没有举例子就很不好(

3.是HTML与JavaScript代码紧密耦合;

如果要更换事件处理程序,就要改动两个地方:HTML代码和JavaScript代码;

而这正是许多开发人员摒弃HTML事件处理程序,转而使用JavaScript指定事件处理程序的原因所在;

DOM0级事件处理程序

将一个函数赋值给一个事件处理程序属性;

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

以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理;

删除事件处理程序;

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

DOM2级事件处理程序

addEventListener(),removeEventListener();

所有DOM节点中都包含这两个方法,并且它们都接受3个参数:

要处理的事件名,作为事件处理程序的函数和一个布尔值;

最后这个布尔值参数如果是true,表示在捕获阶段调用事件处理程序;

如果是false,表示在冒泡阶段调用事件处理程序;

可以添加多个,按照添加顺序触发;

通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;

移除时传入的参数与添加处理程序时使用的参数相同;

这也意味着通过addEventListener()添加的匿名函数将无法移除;

这里回忆一下,匿名函数引发的js内存泄漏;

var btn = document.getElementById("myBtn");
btn.addEventListener("click", function () {
    alert(this.id);
}, false);
//这里省略了其他代码
btn.removeEventListener("click", function () { //没有用!
    alert(this.id);
}, false);

var btn = document.getElementById("myBtn");
var handler = function(){
alert(this.id);
};
btn.addEventListener("click", handler, false);
//这里省略了其他代码
btn.removeEventListener("click", handler, false); //有效!

大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器;

最好只在需要在事件到达目标之前截获它的时候将事件处理程序添加到捕获阶段;

如果不是特别需要,我们不建议在事件捕获阶段注册事件处理程序;

IE事件处理程序

IE可厉害了现在,都是单独一节专门讲了;

attachEvent()和detachEvent();

接收两个参数:事件处理程序名称与事件处理程序函数;

使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window;

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

以及这里是onclick不是click;

也可以添加多个,但是不是以添加顺序执行,而是刚好相反;

同样的,匿名函数不能被移除;

跨浏览器的事件处理程序

该来的总会来;

要保证处理事件的代码能在大多数浏览器下一致地运行,只需关注冒泡阶段;

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);