JavaScript欲速则不达——事件对象和事件委托

基本处理事件详解和阻止事件传播中,我们知道了事件处理程序,今天我们来认识DOM中的事件对象和事件委托。

在触发 DOM 上的某个事件是,会产生 event 事件对象,这个对象包含着所有与事件有关的信息。而且不管是使用DOM0级或DOM2级都会传入 event 对象,只是支持方式不同。虽然DOM和IE中evnet对象不同,但它们之间还是有很多相似性的,所以依旧可以拿出跨浏览器的解决方案来。

在访问 DOM中的 event 对象就有不同,除IE外其他浏览器都可以直接通过 evrnt 对象直接访问,而 IE 访问 event对象则不同:使用DEM0级方法添加事件处理程序,event对象作为window对象的一个属性存在,而通过 attachEvent 添加的,则跟 firefox 、chrome 等浏览器一样直接访问event对象,所以得出一下解决方案:

function(event){
    return event || window.event
}
跨浏览器解决事件对象方案

事件对象

event 对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性也不一样。W3C DOM可用的成员很多,但是可能因为IE只有4个,所以看到也就那4个,如下:

  • 取消冒泡

    IE是 cancelBubble=true就可以取消冒泡

    其他浏览器 event.stopPropagation()就ok了

  • 取消默认行为

    IE是 returnValue =false

    其他浏览器 event.preventDefault()

  • 事件的目标元素

    IE是 srcElement 来获取事件的目标元素

    其他浏览器

    target 来获取事件的目标元素

  • 事件类型

    被触发的事件类型 所有浏览器都是 type

由以上我们得出解决跨浏览器解决事件对象的方案,使用率很高。

var EventUtil = {
    listenEvent:function(eventTarget,eventType,eventHandler){
        eventTarget.addEventListener?
            eventTarget.addEventListener(eventType,eventHandler,false):
            eventTarget.attachEvent?
                eventTarget.attachEvent("on"+eventType,eventHandler):
                eventTarget['on'+eventType]=eventHandler;
},
    stopListening:function(eventTarget,eventType,eventHandler){
        eventTarget.removeEventListener?
        eventTarget.removeEventListener(eventType,eventHandler,false):
        eventTarget.detachEvent?
        eventTarget.detachEvent("on" + eventType,eventHandler):
        eventTarget['on'+eventType] = null;
},
preventDefault: function(eventTarget){
    eventTarget.preventDefault ? eventTarget.preventDefault():eventTarget.returnValue = false;
},
stopPropagation:function(eventTarget){
    eventTarget.stopPropagation ? eventTarget.stopPropagation():eventTarget.cancelBubble = true;
},
evt : function(e){
    return e || window.event;
}
evtTarget:function(e){
    returm e.target||e.srcElement;
}
}
跨浏览器的事件解决方案
  1. listenEvent和stopListening我们在基本处理事件详解和阻止事件传播已经接介绍过了,这里就不再介绍了。
  2. preventDefault(),用于取消事件的默认行为,如果存在 preventDefault() 则调用该方法,如果不存在则将 returnValue 设置为 false。
  3. stopPropagation()与上例类似,首先尝试使用DOM方法阻止时间流,否则使用cancelBubble
  4. evt() 返回对 event 对象的引用,在兼容 DOM 的浏览器中,event只是简单传入,而在IE中,event参数是未定义的 undefined,因此就会返回 window.event。
  5. evtTarget()返回的事件的目标,先检测 event 对象的target属性,存在则返回该值;否者则返回 srcElement。但是又因为 IE中采用DOM0级和采用attachEvent的获取evt方式不同,所以得如下使用:
    event = EventUtil.evt(e);
    var target = EventUtil.evtTarget(e);
    

注意:在IE中因为采用DOM0级方法指定和采用DOM3级指定事件作用域不同,所以 this 不一定指向 事件目标,只有在 使用DOM0级 this指向 事件目标

那事件委托又是什么,跟上面讲的有关系么?当然有,事件委托就是利用事件冒泡远离实现的(当然事件捕获也可以,只是IE没有这个过程)来实现的,而且还用到事件对象中的 目标对象属性。

事件委托

事件委托是一个解决内存和性能的技巧。首先我们得知道为什么添加到页面上的事件处理数量会影响页面整体的运行性能:

  1. 每个函数都是对象,都会占用内存;内存中对象越多,性能越差。
  2. 必须事先指定所有事件处理程序而导致的DOM访问次数,会延迟整个页面的交互就绪事件。

解决 事件处理程序过多 的问题的解决方案就是 事件委托

原理就是:为了不一个个遍历子节点绑定事件处理程序,把事件处理程序只绑定在包含这些子元素的父元素上,点击子节点,由于事件冒泡,绑定在父元素上的事件处理程序被处理,所以用户看到的效果跟遍历节点绑定事件处理程序的效果一样,而事件目标还是被点击的字节点。

而且如果使用遍历字节点去绑定事件处理程序,如果删除子节点,那些绑定在子节点上的事件处理程序还是没有移除的,必须得手动移除,如:element.onclick=null,而采用事件委托也没有这烦恼

使用事件委托,不仅能提高性能,而且加入绑定事件处理程序的父元素中指向事件源的子元素还是有之前的事件的。一般,因为遍历是在新添加元素之前完成的,所以当我们新添加的元素进去后,事件处理程序是不可能绑定进去的。

而事件委托没有这个烦恼,因为他处理程序在父元素上,所以事件委托解决了 提高性能 和 给未来节点添加预期事件处理程序 两个问题 ,可谓一箭双雕。如下实例

//js代码
function changeBackgroundColor(evt,BackColor){
    var evt = evt || window.event;  // IE:window.event
    var target = evt.target || evt.srcElement;// IE:window.event.srcElement
    if(target.nodeName.toLowerCase() == 'li'){
        target.style.backgroundColor = BackColor;
    }
}
window.onload = function(){
    var oUl = document.getElementById('ulBox');
    var aLi = oUl.getElementsByTagName('li');
    var oInput = document.getElementById('input1');
    var iNoww = 4;
    oUl.onmousemove = function(event){
        changeBackgroundColor(event,"red");
    }
    oUl.onmouseout = function(event){
        changeBackgroundColor(event,"");
    }
    oInput.onclick = function(){
        iNoww++;
        var oLi = document.createElement('li');
        oLi.innerHTML = 1 * iNoww;
        oUl.appendChild(oLi);
    }
}
//html代码
<input type="button" value="添加" id="input1" />
<ul id="ulBox">
    <li>1
    <li>1
    <li>3
</ul>

DEMO

  • 1
  • 1
  • 3
事件委托实例

本文源链接:http://www.html5jscss.com/javascript%e6%ac%b2%e9%80%9f%e5%88%99%e4%b8%8d%e8%be%be-%e4%ba%8b%e4%bb%b6%e5%af%b9%e8%b1%a1%e5%92%8c%e4%ba%8b%e4%bb%b6%e5%a7%94%e6%89%98.html

转载请注明《JavaScript欲速则不达——事件对象和事件委托》| html5jscss

评论关闭了.