@lxjwlt
2015-01-02T20:13:24.000000Z
字数 2033
阅读 2714
我:之前研究过jQuery的事件绑定
面试官:不是有addEventListener吗?
我: ......
之前看过jQuery的事件绑定的源代码,惊叹是何等神人能想出这样实现方法,jQuery.on事件绑定不是原生addEventListener
可以代替的,它解决了以下问题:
addEventListener
的全部功能,包括多事件绑定,事件函数按绑定顺序执行addEventListener
内部简单判断一下event.target
就能够实现的如果再有人反着白眼问我,不是有addEventListener
吗?我只想说,jQuery团队在事件绑定上编写的几百行代码可不是白写的。
本文会简要的介绍一下jQuery自定义事件的使用场景。
我们为document
绑定两个click事件:
$(document).on('click', function handler_1() {});
$(document).on('click', function handler_2() {});
我们想一下,jQuery内部是用下面这种形式实现么?
document.addEventListener('click', function handler_1() {});
document.addEventListener('click', function handler_2() {});
是也不是,因为元素的事件绑定肯定是要用到addEventListener
的,但在jQuery内部实现中,每个元素对应的每个事件,只会调用一次addEventListener
,用来触发事件分派函数
document.addEventListener('click', function() {
// 筛选并调用符合条件的事件函数
});
handler_1,handler_2两个事件函数去哪了?实际上,jQuery是利用jquery.data
函数将这两个函数存在document
专属的存储空间里,当触发了click事件的同时也触发了事件分派函数,该函数会遍历document
专属的存储空间,根据一系列的条件筛选事件函数,这些条件包括子选择符,事件组名等等,最后将筛选出来的函数一一执行。
由于jQuery这种实现事件绑定的机制,自定义事件变得非常简单。
$(document).on('smile', function () {});
上述代码,document
元素绑定了一个自定义事件smile,我们可以用trigger或triggerHandler来触发这个事件:
$(document).trigger('smile');
$(document).triggerHandler('smile');
trigger和triggerHandler的区别在于,trigger方法触发的事件会顺着DOM树向上冒泡,而triggerHandler方法只是调用该元素上对应的事件函数,不会冒泡。
自定义事件一般用于给元素绑定一系列的动作,比如,我们要实现弹框效果,我们需要一个掩层和若干窗体。
<div id="overlay">
<div class="window window--login"></div>
<div class="window window--register"></div>
...
</div>
弹框需要两个动作: 关闭窗体和打开窗体。考虑到窗体可能动态增加,我们用到了动态事件绑定(动态绑定的原理在于,子元素触发的事件总会冒泡到父元素上,所以我们只需要把事件函数绑定在父元素上)
$('#overlay').on('close', '.window', function() {});
$('#overlay').on('open', '.window', function() {});
由于动态绑定依赖冒泡来触发事件函数,所以当我们 只能使用 trigger,来触发动态绑定的事件。比如我们要打开登录窗口:
$('.window--login').tigger('open');
通过自定义事件,我们将DOM元素和其DOM操作一一对应起来。
如果某些情况下,我们需要知道事件函数的返回值,我们可以用jQuery.Event
生成一个event对象,用这个对象来触发事件函数,事件函数的返回值将保存在event对象的result属性中,这样,我们就能够获取事件函数的返回值了:
$(document).on('customEvent', function() { return 'hello world!'; });
var event = $.Event('customEvent');
$(document).trigger(event);
event.result; // 'hello world'