JavaScirpt事件处理

一、事件流

事件流,描述的是页面中接受事件的顺序,不过,IE的事件流是事件冒泡流,而Netscape Communicator的事件流是事件捕获型。标准同时支持两种事件模型,即捕获型事件与冒泡型事件,但是,捕获型事件先发生。

两种事件流都会触发DOM中的所有对象,从document对象开始,也在document对象结束(大部分兼容标准的浏览器会继续将事件是捕捉/冒泡延续到window对象)JavaScript与HTML之间的交,通过事件实现。常用观察员模式,使用侦听器来预定事件,以便事件发生时执行相应的代码。

DOM(文档对象模型)结构是一个树型结构,当一个HTML元素产生一个事件时,该事件会在元素结点与根节点之间按特定的顺序传播,路径所经过的节点都会收到该事件,这个传播过程可称为DOM事件流。

二、事件句柄和事件监听器

事件句柄与事件监听器的最大不同之处是使用事件句柄时一次只能插接一个事件句柄,但对于事件监听器,一次可以插接多个。现在大多数浏览器都内置了一些更高级的事件处理方式,即,事件监听器,这种处理方式就不受一个元素只能绑定一个事件句柄的限制。

获取事件的目标

HTML如下:

body id="myBody">
    <button id="myButton">click</button>
</body>

1. IE下的事件监听器:attachEvent接受两个参数。第一个参数是事件类型名,第二个参数eventListener是回调处理函数。

在IE中,每个元素和window对象都有两个方法:attachEvent方法和detachEvent方法。

IE 事件对象使用 event 的 srcElement 属性获取事件目标。

var btn = document.getElementById("myButton");
btn.attachEvent("onclick", function(event) {
    alert(event.srcElement.id);    // myButton
});

2. DOM标准下的事件监听器:addEventListener

addEventListener方法接受三个参数。第一个参数是事件类型名,值得注意的是,这里事件类型名称与IE的不同,事件类型名是没’on’开头的;第二个参数eventListener是回调处理函数(即监听器函数);第三个参数注明该处理回调函数是在事件传递过程中的捕获阶段被调用还是冒泡阶段被调用 ,通常此参数通常会设置为false(为false时是冒泡),如果将其值设置为true,那就创建一个捕捉事件监听器。

通过addEventListener方法添加的事件处理函数,必须使用removeEventListener方法才能删除,而且要求参数与添加事件处理函数时addEventListener方法的参数完全一致(包括useCapture参数),否则将不能成功删除事件处理函数。

标准事件对象使用 event 的 target 属性获取事件目标:


var btn = document.getElementById('myButton');
btn.addEventListener("click", function(event) {
    alert(event.target.id);    // myButton
});

三、取消事件默认行为

html结构如下:

<div id="oDiv">
    <a id="oA" href="http://baidu.com">
        百度一下,你就知道。
    </a>
</div>

正常情况下,我们点击a链接,会跳转到baidu.com,但当使用了e.preventDefault().

JS代码如下:

var a = document.getElementById("oA");

    //获取div
    var oDiv = document.getElementById('oDiv');

        //dom0级绑定事件方法
        a.onclick=function(e){
            e.preventDefault();
        }
   // 旧版本IE不支持捕获,一般使用冒泡。
        oDiv.addEventListener("click", function (e) {
            e.preventDefault();
        }, false);

四、禁止冒泡

一、正常情况下:

//关于阻止事件冒泡.ie678用attachEvent
    a.addEventListener("click", function (e) {
        alert(1);
    }, false);//冒泡


    oDiv.addEventListener("click", function (e) {
        alert(2)
    }, false);//冒泡

    oDiv.addEventListener("click", function (e) {
        alert(3);
    }, true);//捕获,捕获先发生

第3个参数设置为false时候为冒泡,先捕获,后冒泡。这里弹出顺序依次是:3,1,2

二、禁止冒泡时:用到stopPropagation

    //关于阻止事件冒泡.ie678用attachEvent
    a.addEventListener("click", function (e) {
        e.stopPropagation();//阻止冒泡/捕获
        alert(1);
    }, false);//冒泡


    oDiv.addEventListener("click", function (e) {
        alert(2)
    }, false);//冒泡

    oDiv.addEventListener("click", function (e) {
        e.stopPropagation();
        alert(3);
    }, true);//捕获,捕获先发生

这时候顺序是:3,不会出现1,2。因为在第3个函数里用到了stopPropagation,而且捕获比冒泡事件先发生。所以只会出现3.

注意:e.cancelBubble = true对应取消冒泡;e.returnValue = true对应阻止默认行为

五、addEventListener与attachEvent区别

1. 支持的浏览器

    addEventListener在支持DOM2的浏览器中使用,如FF, Chrome等

    attachEvent为IE所用

2. 处理程序执行阶段

    addEventListener的第三个参数为true时,在捕获阶段执行,为false时,在冒泡阶段执行

    attachEvent的均在冒泡阶段执行

3. 作用域

    addEventListener的作用域为元素作用域,this为element的引用

    addEvent的为全局作用域,this为window的引用

4. 事件处理程序执行顺序

    addEventHander:执行顺序与添加顺序一致

    attachEvent:执行顺序与添加顺序相反

5. 针对的事件不同

    attachEvent中的事件带on 
 
    addEventListener中的事件不带on

六、冒泡的用处

例如:有一个10列、100行的HTML表格,假如有一次你需要让表格中的每一个单元格在被点击的时候变成可编辑状态。

如果把事件处理器加到这1000个单元格会产生一个很大的性能问题,并且有可能导致内存泄露甚至是浏览器的崩溃。

相反地,使用事件代理的话,只需要把一个事件处理器添加到table元素上就可以了,这个函数可以把点击事件给截下来,并且判断出是哪个单元格被点击了。

比如:有一个 table元素,ID是“report”,我们为这个表格添加一个事件处理器以调用editCell函数。editCell函数需要判断出传到table 来的事件的目标元素。考虑到我们要写的几个函数中都有可能用到这一功能,所以我们把它单独放到一个名为getEventTarget的函数中:


function getEventTarget(e) {
  e = e || window.event;
  return e.target || e.srcElement;
}

e这个变量表示的是一个事件对象,我们只需要写一点点跨浏览器的代码来返回目标元素,在IE里目标元素放在srcElemtn属性或event.toElement属性中,而在其它浏览器里则是target或event.relatedTarget属性。

接下来就是editCell函数了,这个函数调用到了 getEventTarget函数。一旦我们得到了目标元素之后,剩下的事情就是看看它是否是我们所需要的那个元素了。

function editCell(e) {
  var target = getEventTarget(e);
  if(target.tagName.toLowerCase() === 'td') {
    // DO SOMETHING WITH THE CELL
  }
}

通过事件冒泡,那些需要创建的以及驻留在内存中的事件处理器少了。这样我们就提高了性能,并降低了崩溃的风险。

参考:《JavaScript高级程序设计》

posted @ 2015-06-03 20:25  青青flye  阅读(155)  评论(0编辑  收藏