通过我的研究,我得出一个结论,一个好的委托方法比直接绑定更好。让我们从乞讨开始。我们知道 dom 事件会从目标元素冒泡到它的父元素、祖父元素,直到 document。尽管 IE 和其他浏览器之间存在一些差异,但Jquery event 创建了一致的跨浏览器行为。因此,这两种方法的明显区别在于:
直接绑定事件将在目标(或其后代)上发生并冒泡到document,而委托只是冒泡到最外面的绑定目标。考虑这个例子:
$("#myBtn").click(function(){
console.log("button was clicked");
});
document.onclick = function(){
console.log("document is clicked");
}
<div id="testDiv" style="background:darkgrey">
<button type="button" id="testBtn">click me</button>
</div>
当点击按钮时,document.onclick 将被触发。
但是,如果替换为委托方法,例如:
$("#myDiv").on("click", "#myBtn", function(){
console.log("myBtn was clicked");
});
document.onclick 不会被触发。同时注意点击最外面的myDiv不会触发事件。
关键点来了。以良好的方式使用委托方法将极大地提高性能。参见这个例子(从professional javascript for web developer):
<ul id="myLinks">
<li id="goSomewhere"> Go somewhere </li>
<li id="doSomething"> Do something </li>
<li id="sayHi"> Say hi </li>
</ul>
传统的直接绑定方式是:
$("#goSomewhere").click(function(){
window.location.href = "http://sample.com";
});
$("#doSomething").click(function(){
window.title = "I change the title";
});
$("#sayHi").click(function(){
alert("hi");
});
如果点击事件多,绑定操作的次数会消耗大量内存,页面初始时间也会很长。我们可以通过委托减去一个绑定操作:
$("#myLink").on("click", function(event){
switch(event.target.id){
case: "goSomewhere":
window.location.href = "http://sample.com";
break;
case: "doSomething":
window.title = "title was changed";
break;
case: "sayHi":
alert("hi");
break;
}
});
这会减少大量内存的使用。为了更实用,如果有很多情况,您可能需要使用object 替换switch-case 模块以提高性能,例如:
var eventHandler = {
goSomewhere: function(){ window.location = "http://sample.com"; },
doSomething: function(){ window.title = "title changed"; },
sayHi: function(){alert("hi"); }
}
$("#myLink").on("click", function(event){
if(eventHandler[event.target.id]) eventHandler[event.target.id]();
});
因为 javascript 的对象实际上是一个哈希表。
然后,有一个想法:只需将单个事件附加到document 即可处理所有事件。对于mousedown、click、keydown等事件很实用,不适用于mouseout、mousein。优点很明显:我们只是绑定一个导致更少内存的事件,轻松删除事件处理程序,无需等待文档就绪事件,因为 document 已经可见,因为它的子 script 被读取。在联系中,如果你只是将每一个事件都绑定到document,那么优势就没有了。
另外,如果使用直接绑定还有一个陷阱,例子来自jquery:考虑一个有1000行的表:
$( "#dataTable tbody tr" ).on( "click", function() {
console.log( $( this ).text() );
});
这会将处理程序附加到 1000 tr!但以下只是tbody 的单个附件:
$( "#dataTable tbody" ).on( "click", "tr", function() {
console.log( $( this ).text() );
});