var btn = document.getElementById("myBtn"); // 无法删除匿名函数 btn.addEventListener("click", function() { console.log(this.id); }, false); btn.removeEventListener("click", function() { console.log(this.id); }, false); // 正确的添加和删除方式 function handler() { console.log(this.id); } btn.addEventListener("click", handler, false); btn.removeEventListener("click", handler, false);
大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度地兼容各种浏览器。最好只在需要在事件到达目标之前截获它的时候才将事件处理程序添加到捕获阶段。JS高级程序设计上给出的建议是,如果不是特别需要,不建议在事件捕获阶段注册事件处理程序。
IE事件处理程序
IE实现了与DOM中类似的两个方法: attachEvent()和deleteEvent()。这两个方法接收两个参数,事件处理程序名称和事件处理程序。注意,第一个参数是事件处理程序名称而不是事件名称,也就是说在注册点击事件的处理程序时应该传入”onclick”而不是”click”,这里跟DOM的方法有些差别。另外,这两个方法注册的事件处理程序是在全局作用域中运行而不是元素作用域,this的值指向window。还有一点需要特别小心,通过attachEvent()方法也可以添加多个事件处理程序,但是它们的执行顺序却不是按照它们被添加的顺序,而是完全相反,跟DOM方法截然不同。突然觉得IE真的特别反人类~~~下面是代码示例:
var btn = document.getElementById("myBtn"); function handler1() { // ... } function handler2() { // ... } // 添加,触发点击事件时先执行handler2再执行handler1 btn.attachEvent("onclick", handler1); btn.attachEvent("onclick", handler2); // 删除 btn.deleteEvent("onclick", handler1); btn.deleteEvent("onclick", handler2);
三、事件对象
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
DOM中的事件对象
兼容DOM的浏览器会将一个event对象传入事件处理程序中,无论指定事件处理程序时用的是DOM0还是DOM2的方法,都会传入event对象。event对象只有在事件处理程序执行期间才会存在,一旦事件处理程序执行完毕,event对象就会被销毁。下面是代码示例:
var btn = document.getElementById("myBtn"); btn.onclick = function(event) { console.log(event.type); // "click" } btn.addEventListener("click", function(event) { console.log(event.type); }, false);
event对象包含与创建它的特定事件有关的属性和方法,触发的事件类型不一样,可用的属性方法也有所不同。但是所有的事件都会有下列的属性或方法:
bubbles: 布尔值,表示事件是否冒泡
cancelable: 布尔值,表示是否可以取消事件的默认行为
currentTarget: 元素,事件处理程序当前正在处理事件的那个元素
defaultPrevented: 布尔值,表示是否调用过preventDefault()方法
detail: 整数,与事件相关的细节信息
eventPhase: 整数,调用事件处理程序的阶段,1表示捕获阶段,2表示目标阶段,3表示冒泡阶段
preventDefault(): 函数,取消事件的默认行为,cancelable为true时可以调用该方法
stopImmediatePropagation(): 函数,取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用
stopPropagation(): 函数,取消事件的进一步捕获或冒泡,bubbles为true时可以调用这个方法
target: 元素,事件的目标
trusted: 布尔值,为true时表示事件是浏览器生成的,否则表示事件是通过JS创建的
type: 字符串,被触发的事件类型
view: 与事件关联的抽象视图,等同于发生事件的window对象
下面代码示例展示了上述部分属性的用法,也可以帮助我们进一步理解事件流。假设页面中有一个按钮”myBtn”。当点击按钮时,this和currentTarget都等于body元素,因为事件处理程序是注册在body元素上。target的值却等于按钮元素,因为它是click事件的真正目标。由于按钮上没有注册事件处理程序,结果”click”事件冒泡到了document.body那里才得到处理。
document.body.onclick = function(event) { console.log(event.currentTarget === document.body); // true console.log(this === document.body); // true console.log(event.target === document.getElementById("myBtn")); // true };
再看一个例子,下面代码中,stopPropagation()方法取消了事件的进一步捕获或冒泡。当我点击按钮时,本来应该会因为事件冒泡机制触发按钮和body元素上的点击事件处理程序,输出”From Bth …”和”From Body …”。现在点击事件在按钮元素上触发之后就被阻止继续在DOM层次中的传播,因此body上的事件处理程序不会被触发。