JavaScript入门教程

JavaScript简介
JavaScript语法基础
JavaScript流程控制
JavaScript函数
面向对象编程
JavaScript事件
JavaScript DOM
正则表达式
JavaScript BOM
AJAX

专题分析

浏览器兼容性
JS优化
Web前端开发规范
编辑器推荐
总结和笔记

学习助手

对象参考手册
ECMAScript分析
数据中心
QQ交流群

jQuery自定义事件

自定义事件是jQuery 被低估的特性之一,它简化了强大分布式事件系统向任何Web 应用程序的移植,而且无需额外的库。在jQuery 中,可以使用trigger 方法基于任意DOM元素触发任何想要的事件。
$('#tabby, #socks').on('meow', function() {
    console.log(this.id + ' meowed');
});
$('#tabby').trigger('meow'); // "tabby meowed"
$('#socks').trigger('meow'); // "socks meowed"
如果以前用过DOM 事件,则肯定熟悉冒泡技术。只要某个DOM 元素触发了某个事件(譬如'click'事件),其父元素就会接着触发这个事件,接着是父元素的父元素,以此类推,一直上溯到根元素(即document ), 除非在这条冒泡之路的某个地方调用了事件的stopPropagation 方法。(如果事件处理器返回false,则jQuery会替我们自动调用stopPropagation 方法。)但你是否也知道jQuery自定义事件的冒泡技术呢?举个例子,假设有个名称为“soda”的span元素嵌套在名称为“bottle”的div 元素中,代码如下。
$('#soda, #bottle').on('fizz', function() {
    console.log(this.id + ' emitted fizz');
});
$('#soda').trigger('fizz');
得到的输出如下:
soda emitted fizz
bottle emitted fizz

这种冒泡方式并非始终受人欢迎,从下面的tooltip(工具提示条)示例就能看到这一点。幸运的是,jQuery 同样提供了非冒泡式的triggerHandler 方法。

示例:工具提示条

事件直观映射至页面元素之后,jQuery 就成为分发这些事件的一种理想方式。举个例子,假设正在编写一个关于工具提示条的库,并希望任一时刻只能看到一个工具提示条。我们可能会简单地写下这行代码:
$('.tooltip').remove();
并将它添加到那个负责新添工具提示条的函数的开头。但后来我们又想独立出某些容器(譬如,当侧边栏显示新的工具提示条时,其他地方的工具提示条不受影响),该怎么办?如果反过来,又该怎么办?

编写一个选择器来选中“那些类别为tooltip 且不是sidebar 后代的DOM 元素”,这显然很复杂,而且会非常没有效率。如果允许独立容器作任意深度的嵌套,这个问题的难度还会呈指数级增长。

不过,利用事件逻辑而不是选择器逻辑来实现这一行为则会很容易。
// $container could be $('#sidebar') or $(document)
$container.triggerHandler('newTooltip');
$container.one('newTooltip', function() {
    $tooltip.remove();
});
请注意这里使用了jQuery 的one 来代替on。这两者的区别在于,one 在触发处理器之后会自动将其删除。

有了这两行代码之后,所有的工具提示条都会监听自己的容器,并且每当容器获得新工具提示条时就移除自己。这种优美、直接、有效的方式拯救了我们,让我们无需存储任何状态,也不用鼓弄那些复杂的选择器。(复杂选择器会让那些旧式浏览器慢得像乌龟爬——在不遍历整个文档的情况下,IE7 及更早版本甚至都无法选中类别为tooltip 的所有DOM 元素!)

请注意,实际上在这个案例中事件冒泡技术会破坏我们的意图:希望在侧边栏新建一个工具提示条时, 只有那些监听侧边栏之'newTooltip'事件的工具提示条消失不见,而那些监听外围document元素的工具提示条不受影响。请始终认真思考这个问题:trigger 或triggerHandler,到底哪一个才是完成该任务的合适工具?

jQuery 自定义事件是PubSub 模式的忤逆产物,因为这里由可选择的DOM 元素而不是脚本中的对象来触发事件。事件化模型更像是一种直观表达状态相关事件的方式,而jQuery 的自定义事件允许直接通过DOM 来表达DOM 相关的事件,不必再把DOM 变化的状态复制到应用程序的其他地方。请大方地取用这些特性,但要尽量避免依赖应用程序的标记语言结构——你肯定不希望下次修改设计的时候破坏自己的脚本。