浏览器事件机制与自定义事件的实现

一、 0 级 DOM 上的事件和 2 级 DOM 事件机制

0 级 DOM 上的事件又称原始事件模型,所有的浏览器都支持他,而且是通用的。 2 级 DOM 事件机制又为标准事件模型,除了 ie 其他浏览器都支持( ie9 据说也支持,有待考证), ie 虽然大部分与标准事件模型一样,但有自己专有的事件模型,因此开发人员要实现标准事件模型必须为 IE 写特定的代码,这给程序员增加了负担。

原始事件模型

1.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2.<html>
3.  <head>
4.    <title>浏览器0级DOM上的事件</title>
5.    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
6.  </head>
7.
8.  <body>
9.    <input type="button" value = "点击我" id = "btn">
10.  </body>
11.</html>
12.
13.<script type="text/javascript">
14.<!--
15.var method1 = function(){alert(1)};
16.var method2 = function(){alert(2)};
17.var method3 = function(){alert(3)};
18.document.getElementById("btn").onclick = method1;
19.document.getElementById("btn").onclick = method2;
20.document.getElementById("btn").onclick = method3;
21.//-->
22.</script>

以上书写在各浏览器中都是兼容的,但只有 medhot3 被执行,即同一个对象同一类型的事件只能注册一个处理函数,要想实现注册多个处理函数,需要利用 2 级 DOM 事件机制。

1.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2.<html>
3.  <head>
4.    <title>浏览器2级DOM事件机制</title>
5.    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
6.  </head>
7.
8.  <body>
9.    <input type="button" value = "点击我" id = "btn">
10.  </body>
11.</html>
12.
13.<script type="text/javascript">
14.<!--
15.var method1 = function(){alert(1)};
16.var method2 = function(){alert(2)};
17.var method3 = function(){alert(3)};
18.
19.//执行顺序为method1->method2->method3
20.//标准事件模型
21.var btn1Obj = document.getElementById("btn");
22.btn1Obj.addEventListener("click",method1,false);
23.btn1Obj.addEventListener("click",method2,false);
24.btn1Obj.addEventListener("click",method3,false);
25.
26.//执行顺序为method3->method2->method1
27.//IE事件模型
28.var btn1Obj = document.getElementById("btn");
29.btn1Obj.attachEvent("onclick",method1);
30.btn1Obj.attachEvent("onclick",method2);
31.btn1Obj.attachEvent("onclick",method3);
32.
33.//-->
34.</script> 

从运行结果来看, ie 和 firefox 下执行的顺序是不一样的

二、2级DOM事件模型事件的注册与删除

element.addEventListener(eventType,fn,useCapture); // 注册事件

element.removeEventListener(eventType,fn, useCapture);// 删除事件

可以用 addEventListener() 给同一个对象同一类型的事件注册多个处理函数,但是如果在同一元素上多次注册了一个处理函数,那么第一次注册后的所有注册都将被忽略,但删除该注册函数(调用 removeEventListener() )后可以再重新注册该函数。需要注意的是删除事件, useCapture 的值必须要跟注册时保持一致

1.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2.     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3.<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
4.<head>
5.<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
6.<title>浏览器事件机制——注册和删除事件</title>
7.<style>
8.     div {border:1px  solid blue;}
9.     div#div1 {padding:40px;background-color:#aaaaaa;}
10.     div#div2 {padding:40px;background-color:#bbbbbb;}
11.     div#div3 {padding:40px;background-color:#cccccc;}
12.</style>
13.</head>
14. <body>
15.<div id="div1" style="width:100px;height:100px;" >
16.      我是老大, 点击我添加老三的click事件
17.</div>
18.<br/>
19.<div id="div2" style="width:100px;height:110px;" >
20.    我是老二, 点击我删除老三的click事件
21.</div>
22.<br/>
23.<div id="div3" style="width:100px;height:100px;" >
24.    我是老三,是否有click事件,老大老二说了算,呵呵
25.</div>
26.<script>
27.    function click1() {
28.        alert("I am div1,add div3 event");
29.        if(window.addEventListener){
30.            div3.addEventListener("click", click3, false);
31.        }else if (window.attachEvent){
32.            div3.attachEvent("onclick", click3);
33.        }
34.    }
35.    function click2() {
36.        alert("I am div2,remove div3 event");
37.        if(window.addEventListener){
38.            div3.removeEventListener("click", click3, false);
39.        }else if (window.attachEvent){
40.            div3.detachEvent("onclick", click3);
41.        }
42.    }
43.    function click3() {
44.        alert("I am div3");
45.    }
46.
47.    var div1 = document.getElementById("div1");
48.    var div2 = document.getElementById("div2");
49.    var div3 = document.getElementById("div3");
50.
51.    if(window.addEventListener){
52.        div1.addEventListener("click", click1, false);
53.        div2.addEventListener("click", click2, false);
54.    }else if (window.attachEvent){
55.        div1.attachEvent("onclick", click1);
56.        div2.attachEvent("onclick", click2);
57.    }
58.</script>
59.</body>
60.</html>  

三、2级DOM事件冒泡模型(Bubble Model)

在2级DOM事件模型中,事件传播分三个阶段进行,即捕获阶段(capturing)、目标阶段和冒泡阶段(bubbling)。在捕获阶段,事件从Document对象沿着文档树向下传播给目标节点,如果目标的任何一个祖先(不是目标本身)专门注册了捕获事件句柄,那么在事件传播过程中,就会运行这些句柄,在冒泡阶段,事件将从目标元素向上传播回或气泡回Document对象的文档层次。虽然所有事件都受事件传播的捕获阶段的支配,但并非所有类型的事件都起泡。

在注册事件时,useCapture参数确定侦听器是运行于捕获阶段、目标阶段还是冒泡阶段。 如果将 useCapture 设置为 true,则侦听器只在捕获阶段处理事件,而不在目标或冒泡阶段 处理事件。 如果useCapture 为 false,则侦听器只在目标或冒泡阶段处理事件。 要在所有三个阶段都侦听事件,需调用两次 addEventListener,一次将 useCapture 设置为 true,第二次再将useCapture 设置为 false。

1.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2.     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3.<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
4.<head>
5.<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
6.<title>浏览器事件机制——冒泡处理</title>
7.<style>
8.     div {border:1px  solid blue;}
9.     div#divGrandpa {padding:40px;background-color:#aaaaaa;}
10.     div#divFather {padding:40px;background-color:#bbbbbb;}
11.     div#divSon {padding:40px;background-color:#cccccc;}
12.</style>
13.</head>
14. <body>
15.<div id="divGrandpa" style="width:300px;height:200px;" >
16.       <div id="divFather" style="width:200px;height:120px;" >
17.            <div id="divSon" style="width:100px;height:40px;" >
18.                点击我
19.            </div>
20.       </div>
21.</div>
22.<script>
23.    function showSon() {
24.        alert("I am son");
25.    }
26.    function showFather() {
27.        alert("I am father");
28.    }
29.    function showGrandpa() {
30.        alert("I am Grandpa");
31.    }
32.    var grandpa = document.getElementById("divGrandpa");
33.    var father = document.getElementById("divFather");
34.    var son = document.getElementById("divSon");
35.    if(window.addEventListener){
36.        grandpa.addEventListener("click", showGrandpa, false);
37.        father.addEventListener("click", showFather, false);
38.        son.addEventListener("click", showSon, false);
39.    }else if (window.attachEvent){
40.        grandpa.attachEvent("onclick", showGrandpa);
41.        father.attachEvent("onclick", showFather);
42.        son.attachEvent("onclick", showSon);
43.    }
44.</script>
45.</body>
46.</html>  

从运行结果来看,对于ie,在ie(ie8之前的版本,包括ie8)中当点击son节点时,会分别弹出I am son、I am father和I am Grandpa,即事件最先被底层的结点触发,再逐渐上传,直到最外层的结点,冒泡方式为儿子——>父亲的模式;在Firefox等支持标准事件模型的浏览器中,跟addEventListener的Capture参数有关,当设置为true时,为捕获模式,事件会从最顶层的结点往下传输,即 父亲——>儿子的传播模式。当设为false(默认值)时,则会按冒泡模式传递事件。另外由于ie9即支持window.attachEvent,又支持window.addEventListener,所以会根据代码的书写来运行其效果的。

四、如何停止事件的传递

在IE浏览器中可以调用以下代码
event.cancelBubble = true;
在Firefox等遵循W3C规范的浏览器中,可以调用以下代码
e.stopPropagation();

调用以上代码后可以终止事件在传播过程的捕获、目标处理或起泡阶段进一步传播。调用该方法后,该节点上处理该事件的处理程序将被调用,事件不再被分派到其他节点(即不再进一步传播)。
该方法(属性)将停止事件的传播,阻止它被分派到其他 Document 节点。在事件传播的任何阶段都可以调用它。注意,虽然该方法不能阻止同一个 Document 节点上的其他事件句柄被调用,但是它可以阻止把事件分派到其他节点。

1.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2.     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3.<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
4.<head>
5.<meta http-equiv="Content-Type" content="text/html; charset=utf-8"    />
6.<title>浏览器事件机制——停止事件的进一步传递</title>
7.<style>
8.     div {border:1px  solid blue;}
9.     div#divGrandpa {padding:40px;background-color:#aaaaaa;}
10.     div#divFather {padding:40px;background-color:#bbbbbb;}
11.     div#divSon {padding:40px;background-color:#cccccc;}
12.</style>
13.</head>
14. <body>
15.<div id="divGrandpa" style="width:300px;height:200px;" >
16.       <div id="divFather" style="width:200px;height:120px;" >
17.            <div id="divSon" style="width:100px;height:40px;" >
18.                点击我
19.            </div>
20.       </div>
21.</div>
22.
23.<script>
24.    function showSon(e) {
25.        alert("I am son");
26.    }
27.    function showFather(e) {
28.        //IE把event对象作为window对象的一个属性,而W3C把event对象作为处理程序的一个参数
29.        ee = e || event;
30.        if(e.stopPropagation){
31.            e.stopPropagation();
32.        }else{
33.            e.cancelBubble = true;
34.        }
35.        alert("I am father");
36.    }
37.    function showGrandpa(e) {
38.        alert("I am Grandpa");
39.    }
40.    var grandpa = document.getElementById("divGrandpa");
41.    var father = document.getElementById("divFather");
42.    var son = document.getElementById("divSon");
43.    if(window.addEventListener){
44.        grandpa.addEventListener("click", showGrandpa, false);
45.        father.addEventListener("click", showFather, false);
46.        son.addEventListener("click", showSon, false);
47.    }else if (window.attachEvent){
48.        grandpa.attachEvent("onclick", showGrandpa);
49.        father.attachEvent("onclick", showFather);
50.        son.attachEvent("onclick", showSon);
51.    }
52.</script>
53.</body>
54.</html>  

五、自定义事件

1、不带参数事件处理,也是最简单的事件设计模式

最简单的一种模式是将一个类的方法成员定义为事件,通常是一个空函数,当程序需要处理该事件时,再进行扩充该事件接口。比如:

1.function Class1(){
2.        //构造函数
3.    }
4.    Class1.prototype = {
5.        show : function(){
6.            this.onShow();//触发onShow事件
7.        },
8.        onShow : function(){}//定义事件接口
9.    }
10.    //创建class1实例
11.    var obj = new Class1();
12.    //创建obj的onShow事件处理程序
13.    obj.onShow = function(){
14.        alert(‘onshow event‘);
15.    }
16.    //调用obj的show方法
17.    obj.show();  

2、给事件处理程序传递参数

1.//将有参数的函数封装为无参数的函数
2.    function createFunction(obj, strFn){
3.        obj = obj || window;
4.        var args = [];
5.        for(var i = 2; i < arguments.length; i++){
6.            args.push(arguments[i]);
7.        }
8.        return function(){
9.            //该语句相当于obj[strFn](args[0],args[1],...);
10.            obj[strFn].apply(obj,args);
11.        }
12.    }
13.    //定义类 Class1
14.    function Class1(){
15.        //构造函数
16.    }
17.    Class1.prototype = {
18.        show : function(){
19.            this.onShow();//触发onShow事件
20.        },
21.        onShow : function(){}//定义事件接口
22.    }
23.    //创建class1实例
24.    var obj = new Class1();
25.    //创建obj的onShow事件处理程序
26.    function objOnShow(userName){
27.        alert(‘hello, ‘ + userName);
28.    }
29.    var userName = ‘xiaowang‘;
30.    //绑定obj的onShow事件
31.    obj.onShow = createFunction(null,‘objOnShow‘,userName);
32.    //调用obj的show方法
33.    obj.show();  

在以上代码中,将变量userName作为参数传递给了objOnShow事件处理程序。事实上,obj.onShow 得到的事件处理程序并不是objOnShow,而是由createFunction返回的一个无参函数

3、自定义事件支持多绑定

1.//定义类 Class1
2.    function Class1(){
3.        //构造函数
4.    }
5.    Class1.prototype = {
6.        show : function(){
7.            //如果有事件绑定则循环onshow数组,触发该事件
8.            if(this.onshow){
9.                for(var i = 0, len = this.onshow.length; i < len; i++){
10.                    this.onshow[i]();//调用事件处理程序
11.                }
12.            }
13.        },
14.        addEventOnShow : function (_eHandler){
15.            this.onshow = this.onshow || [];//用数组存储绑定的事件处理程序引用
16.            this.onshow.push(_eHandler);
17.        }
18.    }
19.    //创建class1实例
20.    var obj = new Class1();
21.    //事件一
22.    function onShow1(){
23.        alert(‘event1‘);
24.    }
25.    //事件二
26.    function onShow2(){
27.        alert(‘event2‘);
28.    }
29.    //绑定事件
30.    obj.addEventOnShow(onShow1);
31.    obj.addEventOnShow(onShow2);
32.    //调用obj的show方法
33.    obj.show();  

4、自定义事件支持带参数的多绑定

1.//将有参数的函数封装为无参数的函数
2.    function createFunction(obj, strFn){
3.        obj = obj || window;
4.        var args = [];
5.        for(var i = 2; i < arguments.length; i++){
6.            args.push(arguments[i]);
7.        }
8.        return function(){
9.            //该语句相当于obj[strFn](args[0],args[1],...);
10.            obj[strFn].apply(obj,args);
11.        }
12.    }
13.    //定义类 Class1
14.    function Class1(){
15.        //构造函数
16.    }
17.    Class1.prototype = {
18.        show : function(){
19.            //如果有事件绑定则循环onshow数组,触发该事件
20.            if(this.onshow){
21.                for(var i = 0, len = this.onshow.length; i < len; i++){
22.                    this.onshow[i]();//调用事件处理程序
23.                }
24.            }
25.        },
26.        addEventOnShow : function (_eHandler){
27.            this.onshow = this.onshow || [];//用数组存储绑定的事件处理程序引用
28.            this.onshow.push(_eHandler);
29.        }
30.    }
31.    //创建class1实例
32.    var obj = new Class1();
33.    //创建obj的onShow事件处理程序
34.    function objOnShow(userName){
35.        alert(‘hello, ‘ + userName);
36.    }
37.    //事件一
38.    var  userName1 = ‘xiaowang‘;
39.    var  onShow1 = createFunction(null,‘objOnShow‘,userName1);
40.    //事件一
41.    var  userName2 = ‘xiaoli‘;
42.    var  onShow2 = createFunction(null,‘objOnShow‘,userName2);
43.    //绑定事件
44.    obj.addEventOnShow(onShow1);
45.    obj.addEventOnShow(onShow2);
46.    //调用obj的show方法
47.    obj.show();  

以上实现把带参数和多绑定结合在一起,还可以增加一个removeEventOnShow来删除已注册的事件。

六、把对象注册为事件句柄

在编写面向对象的JavaScript程序时,如果想用对象作为事件句柄,那么可以使用如下的函数来注册它们:

function registerObjectEventHandler(element,eventtype,listener,captures){
    element.addEventListener(eventtype,
        function(event) {listener.handleEvent(event);},captures);
}

用这个函数可以把任何对象注册为事件句柄,只要它定义了handleEvent()方法。Firefox(以及其他基于Mozilla代码的浏览器)允许直接把定义了handleEvent()方法的事件监听器对象传递给addEventListener()方法而不是函数引用。对于这些浏览器来说,不需要我们刚才给出的特殊注册函数。

请看下面的例子

1.<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2.<html>
3.  <head>
4.    <title>把对象注册为事件句柄</title>
5.    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
6.  </head>
7.
8.  <body>
9.    <input type="button" value = "点击我" id = "btn">
10.  </body>
11.</html>
12.
13.<script type="text/javascript">
14.<!--
15.    var EventHandler = function(){}
16.    EventHandler.prototype.handleEvent = function(event){
17.        alert(‘用对象作为事件句柄,只要实现该对象的方法handleEvent即可‘);
18.        alert(event.type);
19.    }
20.    var objectHandler = new EventHandler();
21.    var btn1Obj = document.getElementById("btn");
22.    if(window.addEventListener){
23.        btn1Obj.addEventListener("click",objectHandler,false);
24.    }else if (window.attachEvent){
25.        //btn1Obj.attachEvent("onclick",objectHandler);//调用失败,说明不支持把对象注册为事件句柄
26.        //btn1Obj.attachEvent("onclick",objectHandler.handleEvent);
27.        registerObjectEventHandler(btn1Obj,"onclick",objectHandler);
28.    }
29.
30.    /**
31.     * 对于不支持把对象注册为事件句柄的浏览器,可以调用以下方法来实现
32.     */
33.    function registerObjectEventHandler(element,eventtype,listener,captures){
34.        if(window.addEventListener){
35.            element.addEventListener(eventtype,
36.                function(event) {listener.handleEvent(event);},captures);
37.        }else if (window.attachEvent){
38.            element.attachEvent(eventtype,
39.                function(event) {listener.handleEvent(event);});
40.        }
41.    }
42.
43.//-->
44.</script> 

浏览器事件机制与自定义事件的实现

时间: 2024-10-12 15:28:20

浏览器事件机制与自定义事件的实现的相关文章

Flex事件机制学习-自定义事件实现类间通信 .

今天,学习Flex自定义事件,可以使两个类通信,定义一个Main类. public class Main extends Sprite     {            public function Main()            { //演示ChildSprite类是与Main类通信,ChildSprite类稍后说明: var child:ChildSprite=new ChildSprite(); //指示该实例的属性值            child.flag="01";

Android事件机制之一:事件传递和消费

http://www.cnblogs.com/lwbqqyumidi/p/3500997.html 关于Android中的事件机制,用到的地方还是很多的,并且这个知识点还真有点复杂. 在写这篇文章前,网上看了不少博文,有的写的感觉挺不错的.只是当时感觉好像理解了,事后又很容易忘.现在自己也系统整理下吧. Android中的事件在表现形式上有很多,如onTach.onClick和onLongClick等,在具体微观上的表现形势有action_down.action_move和action_up等.

通过c# 实现自定义属性改变触发自定义事件 ,理解自定义事件及其触发过程

以下说明可解释自定义的事件的自定义触发过程: 直接上代码,内含说明(界面是两个文本框textbox1,textbox2,和一个button1,界面的Load事件,button的click事件) Form1 类(调用者端) using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; us

Qt事件机制---信号通过事件实现,事件可以过滤,事件更底层,事件是基础,信号是扩展。

Qt事件机制 Qt程序是事件驱动的, 程序的每个动作都是由幕后某个事件所触发.. Qt事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. Qt事件的类型很多, 常见的qt的事件如下: 键盘事件: 按键按下和松开. 鼠标事件: 鼠标移动,鼠标按键的按下和松开. 拖放事件: 用鼠标进行拖放. 滚轮事件: 鼠标滚轮滚动. 绘屏事件: 重绘屏幕的某些部分. 定时事件: 定时器到时. 焦点事件: 键盘焦点移动. 进入和离开事件: 鼠标移入widget之内,或是移出. 移动事件: widget的位

JS过渡结束监听事件及使用自定义事件解决兼容问题的方法

1.JS过渡结束监听事件 2.自定义事件解决兼容问题 原文地址:https://www.cnblogs.com/liu-web-bew/p/9345478.html

js事件模型与自定义事件

JavaScript 一个最简单的事件模型,需要有事件绑定与触发,也许还要有事件删除. 1 var eventModel = { 2 list: {}, 3 4 bind: function () { 5 var args = [].slice.apply(arguments), 6 type = args[0], 7 handlers = args.slice(1); 8 9 if (typeof type === 'string' && handlers.length > 0)

mui 事件管理及自定义事件详解

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" /> <title></title

js中事件(自定义事件)

今天闲的蛋疼,我们来聊一聊web前端中的事件机制和自定义事件.灵感来自jQuery,在此感谢jQuery作者. 首先,最开始. <button id="button" type="button" onclick="alert('hello')">你好</button> 这是我们在使用html写页面的时候最原生的事件触发方式.上面那行代码会生成一个按钮,当我们点击这个按钮的时候就会弹出一个原生的弹窗,内容是hello. 随着

javascript和jquey的自定义事件小结

“通过事件机制,可以将类设计为独立的模块,通过事件对外通信,提高了程序的开发效率.” 可以把多个关联但逻辑复杂的操作利用自定义事件的机制灵活地控制好 对象之间通过直接方法调用来交互 1)对象A直接调用对象B的某个方法,实现交互:直接方法调用本质上也是属于一种特殊的发送与接受消息,它把发送消息和接收消息合并为一个动作完成: 方法调用方和被调用方被紧密耦合在一起:因为发送消息和接收消息是在一个动作内完成,所以无法做到消息的异步发送和接收: 2)对象A生成消息->将消息通知给一个事件消息处理器(Obs