探析事件监听addEventListener

2,364 阅读2分钟

addEventListener参数

任何可支持事件的对象都可以作为事件目标对象,如Element、Document、Window等对象。

  1. 支持可选参数options的浏览器
target.addEventListener(eventType,callback,options)

options={capture:Boolean,once:Boolean,passive:Boolean}

capture:默认为false,表示事件在冒泡阶段触发,true则表示在捕获阶段触发。

once:默认为false,如果为true则事件在被触发后马上清除监听器。

passive:默认为false,但在touchmove和touchend事件时默认为true,为true时表示禁止调用preventDefault()事件。

  1. 现代浏览器,第三个参数可直接转变为useCapture
target.addEventListener(eventType,callback,useCapture)

useCapture:默认为false,在DOM树中冒泡阶段执行回调,设置为true时则在捕获阶段执行回调

之所以有两种不同事件流,是因为微软开发了事件冒泡流,DOM树自下向上依次触发;而网景开发了事件捕获流,DOM树自上向下依次触发。W3c制定标准时,同时兼容了两种事件流,让开发者自行选择。

兼容低版本IE

if (el.addEventListener) {
  el.addEventListener('click', callback, false); 
} else if (el.attachEvent)  {
  el.attachEvent('onclick', callback);
}

节约内存

首先,如果同一个对象监听了相同事件,EventListener并不会多次调用,也不需要用 removeEventListener 手动清除多余的EventListener ,因为重复的都被自动抛弃了,前提是options中的capture的参数值一致,如果capture的值不一致,此时就算重复定义,也不会被抛弃掉。

其次,如果callback被多个监听用到,可以创建一个具名函数,每次监听事件时,引用该函数,就避免了每次创建一个新的单独的函数。

var i;
var els = document.getElementsByTagName('*');

function processEvent(e){
  /*do something*/
}
for(i=0 ; i<els.length ; i++){
  els[i].addEventListener("click", processEvent, false});
}

最后,在元素监听事件执行后,如果不在用到,应该及时清除事件监听,target.removeEventListener(event),释放内存。

passive具体探析

这里主要要说的是passive属性,在触屏事件如touchmove和touchstart时,默认值是true,是为了防止浏览器的上下左右滚屏被干扰。 同理,如果想要阻止触屏浏览器的左右滑屏,可以这样添加事件监听

document.addEventListener('touchmove',(e)=>{e.preventDefault()},{passive:false})

注意:如果浏览器不支持options,则默认转变为useCapture属性。

如果只想阻止左右滑屏,则可以做一个左右位移与上下位移的对比

let start;
document.addEventListener("touchstart",(e)=>{
    start= [e.targetTouches[0].pageX,e.targetTouches[0].pageY];
});
document.addEventListener("touchmove",(e)=>{
    let move = [e.targetTouches[0].pageX, e.targetTouches[0].pageY];
    if(Math.abs(move[0]-start[0])>Math.abs(move[1]-start[1])){
        e.preventDefault();
    }
},{passive:false});