js事件流、事件处理程序/事件侦听器

1、事件流

事件冒泡

IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。

事件捕获

事件捕获的思想是不太具体的节点应该更早的接收到事件,而最具体的节点应该在最后接收到节点。事件捕获的用意在于事件到达预定目标之前捕获它。

DOM事件流

“DOM2级事件流”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出响应。以简单的HTML页面为例,单击<div>元素会按照下图顺序触发事件

在DOM事件流中,实际的目标(<div>元素)在捕获阶段不会接收到事件。这意味着在捕获阶段,事件从document到<html>再到<body>后就停止了。下一个阶段是“处于目标”阶段,于是事件在<div>上发生,并在事件处理中被看成冒泡阶段的一部分。然后冒泡阶段发生,事件又传播回文档。

多数支持DOM事件流的浏览器都实现了一种特定行为;即使“DOM2级事件”规范明确要求捕获阶段不会涉及事件的目标,但Safari、Chrome、Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件。结果,就是有两个机会在目标对象上面操作事件。

Opera、Firefox、Chrome和Safari都支持DOM事件流;IE不支持DOM事件流。

2、事件处理程序(或事件侦听器)

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

HTML事件处理程序

某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性指定。如:

<input type="button" value="Click me"  onclick="alert(‘Clicked‘)"/>
<script type="text/javascript">
    function showMessage(){
        alert("Hello World!");
    }
</script>
<input type="button" value="Click me"  onclick="showMessage()"/>

在HTML中指定事件有两个缺点。首先,存在一个时差问题。因为用户可能在HTML元素一出现在页面上就触发相应的事件,但当时事件处理程序有可能尚不具备执行条件。例如前面的例子,假设showMessage函数在按钮下方页面最底部定义的,如果用户在页面解析showMessage函数之前就单击了按钮,就会引发报错。第二个确定是HTML与JavaScript代码紧密耦合。如果要更换事件处理程序,就要改动两个地方。

DOM0级事件处理程序

通过JavaScript指定事件处理程序的传统方式,就是讲一个函数赋值给一个事件处理程序属性。要使用JavaScript指定事件处理程序,首先必须取得一个要操作的对象的引用。

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

使用DOM0级方法指定的事件处理程序被认为是元素的方法,因此是在元素的作用域中运行,换句话说,程序中的this引用当前元素。

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

可以在事件处理程序中通过this访问元素的任何属性和方法,以这种方式添加的事件处理程序会在事件流中的冒泡阶段被处理。

可以删除通过DOM0级方法指定的事件处理程序,只要将事件处理程序属性的值设为null即可。

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

DOM2级事件处理程序

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

与DOM0级方法一样,DOM2级方法天际的事件处理程序也是在其依附的元素的作用域中进行。使用DOM2级方法添加事件处理程序的主要好处是可以添加多个事件处理程序。来看下面的例子:

btn.addEventListener("click",function(){
    alert(this.id);
},false);
btn.addEventListener("click",function(){
    alert("Hello World!");
},false);

这里为按钮多添加了两个事件处理程序。这两个事件处理程序会按照添加它们的顺序触发,因此首先会显示元素ID,其次会显示“Hello World!”消息。

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

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);  //有效!

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

Firefox、Safari、Chrome和Opera支持DOM2级事件处理程序

IE事件处理程序

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

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

注意:第一个参数为“onclick”,而非DOM的addEventListener()方法中的"click"。

在IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的作用域。DOM0级事件处理程序会在其所属元素的作用域内运行;在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。在编写跨浏览器的代码时,牢记这一点区别非常重要。

attachEvent()也可以为一个元素添加多个事件处理程序,来看下面的例子:

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

与DOM方法不同的是,这些事件处理程序不是以添加它们的顺序执行,而是以相反的顺序被触发。单击这个例子中的按钮,首先看到的是“Hello World!”,然后才是“Clicked”。

使用attachEvent()添加的事件可以通过detachEvent()来移除,条件是必须提供相同的参数。与DOM方法一样,添加的匿名函数将不能被移除。

var btn = document.getElementById("myBtn");
var handler = function(){
    alert("Clicked");
};
btn.attachEvent("onclick",handler);
btn.detachEvent("onclick",handler); 
时间: 2024-08-07 17:00:25

js事件流、事件处理程序/事件侦听器的相关文章

Android事件侦听器回调方法浅谈

http://developer.51cto.com/art/201001/180846.htm Android事件侦听器作为视图View类的接口,其中包含有不少回调方法,比如:onClick():onLongClick():onFocusChange():onKey():onTouch():onCreateContextMenu()等等. Android操作系统中,对于事件的处理是一个非常基础而且重要的操作.许多功能的实现都需要对相关事件进行触发才能达到自己的目的.比如Android事件侦听器

DOM事件: DOM事件级别、DOM事件流、DOM事件模型、DOM事件捕获过程、自定义事件

前端面试中只要问到事件,就肯定会有DOM事件:如果回答出来了,就会一直向下延申,其实这些东西都很简单,但我第一次被问到的时候,也是懵的: DOM事件级别: DOM0 element.onclick = function() { } DOM1 一般只有设计规范,没有设计跟事件相关的东西:所以直接跳过 DOM2 element.addEventListener(‘click’, function() { }, false) DOM3 element.addEventLIstener(‘keyup’,

IE和DOM事件流、普通事件和绑定事件的区别

IE和DOM事件流的区别 IE采用冒泡型事件 Netscape(网络信息浏览器)使用捕获型事件 DOM使用先捕获后冒泡型事件 示例: <body> <div> <button>click</button> </div> </body> 冒泡型事件模型:button->div->body (IE事件流) 捕获型事件模型:body->div->button (Netscape事件流) DOM事件模型:body-&g

Vue.js 实战教程 V2.x(7)计算属性和侦听器

7计算属性和侦听器 7.1计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的. 在模板中放入太多的逻辑会让模板过重且难以维护. 所以,对于任何复杂逻辑,你都应当使用计算属性. 基础例子 <div id="example"> <p>Original message: "{{ message }}"</p> <p>Computed reversed message: "{{ reversedMe

5.计算属性和侦听器

计算属性 所以,对于任何复杂逻辑,你都应当使用计算属性.  vm.reversedMessage 的值始终取决于 vm.message 的值. 计算属性缓存 vs 方法 你可能已经注意到我们可以通过在表达式中调用方法来达到同样的效果: 不同的是计算属性是基于它们的响应式依赖进行缓存的. 只在相关响应式依赖发生改变时它们才会重新求值.这就意味着只要 message 还没有发生改变, 多次访问 reversedMessage计算属性会立即返回之前的计算结果,而不必再次执行函数. 相比之下,每当触发重

as3 阻止后续侦听器

public class Test1 extends Sprite { private var spr:Sprite; private var spr2:Sprite; public function Test1() { spr = new Sprite(); spr.graphics.beginFill(0xff0000,1); spr.graphics.drawCircle(100,100,10); spr.graphics.endFill(); this.addChild(spr); sp

vue 侦听器watch 之 深度监听 deep

<template> <div> <p>FullName: {{person.fullname}}</p> <p>FirstName: <input type="text" v-model="person.firstname"></p> </div> </template> <script> export default { data(){ ret

怎么配置 Oracle 侦听器来使用SQL操作ST_Geometry

关于这个内容,其实从ArcSDE9.2推出ST_Geometry就让用户感到很有吸引力,而且特别是在ArcSDE9.3之后,用户使用SQL操作ST_geometry越来越多,但是在配置Oracle监听来说总是碰到这样那样的问题,以下就是总结一下配置 Oracle 侦听器来使用SQL操作ST_Geometry . 首先说明一下:如果你的ArcSDE版本是9.2最好不要使用这种方式,因为Bug也是比较多的. 例如:http://support.esri.com/en/knowledgebase/te

VueJs(7)---计算属性和侦听器

计算属性和侦听器 一. 概述 计算属性 模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的.在模板中放入太多的逻辑会让模板过重且难以维护.例如: <div id="example"> {{ message.split('').reverse().join('') }} </div> 在这个地方,模板不再是简单的声明式逻辑.你必须看一段时间才能意识到,这里是想要显示变量 message 的翻转字符串.当你想要在模板中多次引用此处的翻转字符串时,就会更加难以