作为一个前端工程师,事件委托应该是必须掌握的基本知识,大家在面试中几乎都会被问到此问题,由此可见,事件委托的重要性。
在js中,添加到页面上的事件处理程序的数量会直接关系到整个页面的运行性能,曾经我就在开发中因为事件绑定太多造成页面卡死、崩溃的情况,由于每个函数都是一个对象 ,都会占用内存,而内存占用越多,性能也就会越差。在可以使用事件委托的地方我们尽量使用事件委托,以提高性能。事件委托利用了事件冒泡的的原理。
事件注销
若将一个绑定事件的div设为空,那么其上绑定的事件处理程序可能还存在内存中(IE浏览器解析问题),最好的方法时手动移除这个事件处理程序(将其设为null)
<div id="myDiv">
<input type="button" value="Click Me" id="myBtn">
</div>
<script>
var btn= document.querySelector("#myBtn")
btn.onclick= function () {
btn.onclick= null // 移除事件处理程序
document.querySelector("#myDiv").innnerHTML= "Processing..."
}
</script>
通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除;移除时传入的参数与添加处理程序时使用的参数相同。
如果页面在两个页面间来回切换,也可以是单击了“刷新“按钮,内存中滞留的对象数目会越来越多,因为事件处理程序占用的内存并没有释放。(某些浏览器会存在这些问题,特别是IE8及之前版本),所以可以在页面的onunload事件中移除这些事件,但是使用了onunload事件处理程序意味着页面不会被缓存在bfcache中。
事件广播(事件派发,即自定义DOM事件,模拟事件)
//创建一个包含initEventName()方法的事件对象
var event= document.createEvent("EventName")
// 初始化事件对象,接收八个参数
event.initEventName(type,bubbles,cancelable,relatedNode,preValue,newValue,attrName,attrChange)
event.initEventName("focus",true,true)
// 派发事件(可以是dom,也可以是某个父级元素)
document.dispatchEvent(event)
// 接收与绑定事件
el.addEventListener("EventName",function(){},false)
事件模型(我们常用的事件底层是如何实现的)
function Emitter() {
this._listener = [];//_listener[自定义的事件名] = [所用执行的匿名函数1, 所用执行的匿名函数2]
}
//注册事件
Emitter.prototype.bind =function(eventName, callback) {
var listener =this._listener[eventName] || [];//this._listener[eventName]没有值则将listener定义为[](数组)。
listener.push(callback);
this._listener[eventName] = listener;
}
//触发事件
Emitter.prototype.trigger =function(eventName) {
var args = Array.prototype.slice.apply(arguments).slice(1);//args为获得除了eventName后面的参数(注册事件的参数)
var listener =this._listener[eventName];
if(!Array.isArray(listener)) return;//自定义事件名不存在
listener.forEach(function(callback) {
try{
callback.apply(this, args);
}catch(e) {
console.error(e);
}
})
}
//实例
var emitter =new Emitter();
emitter.bind("myevent",function(arg1, arg2) {
console.log(arg1, arg2);
});
emitter.bind("myevent",function(arg1, arg2) {
console.log(arg2, arg1);
});
emitter.trigger('myevent',"a","b");