以下见解基于jquery v1.12.4
jquery的on() 方法在被选元素及子元素上添加一个或多个事件处理程序
$(selector).on(event,childSelector,data,function)
一直比较好奇jquery是怎么处理多个参数可以只传几个,且顺序不强制的,遂琢磨了下jquery的on方法
1、 dom结构
<div id="div1">
<p id="p1" class="p-text">文本1</p>
<p id="p2" class="p-text">文本2</p>
</div>
复制代码
2、 基本用法
2.1、 最简单的用法
// 点击#div1打印 *点击了*
$('#div1').on('click', function (e) {
console.log('点击了')
})
复制代码
2.2、 事件委托
// 点击任意p标签打印 *点击了*
$('#div1').on('click', 'p', function (e) {
console.log('点击了')
})
复制代码
2.3、 参数齐全的事件绑定
// 打印出*123*
$('#div1').on('click', 123, function (e) {
console.log(e.data)
})
// 点击不会发生任何事情
$('#div1').on('click', '123', function (e) {
console.log(e.data)
})
复制代码
问题来了,在事件委托那里,我传入的第2个元素是字符串'p',在这里传入字符串'123'点击毫无反应,传入数字123则可以触发。对比on方法的参数顺序,可以发现以上三种例子的顺序都不对应 这就引出了我一开始的问题:jquery是怎么处理多个参数可以只传几个,且顺序不强制的
通过研究一波jquery源码发现,其实原理很简单,就是对传入的参数进行(类型、null、undefined)判断 在jquery内部,会按on方法提供的(约定的)顺序对传入的参数进行判断并转换成其需要的顺序
截取部分代码:
if ( data == null && fn == null ) {
// ( types, fn )
fn = selector;
data = selector = undefined;
} else if ( fn == null ) {
if ( typeof selector === "string" ) {
// ( types, selector, fn )
fn = data;
data = undefined;
} else {
// ( types, data, fn )
fn = data;
data = selector;
selector = undefined;
}
}
复制代码
源码位置:function on( elem, types, selector, data, fn, one )
3、 批量绑定事件
3.1、 批量绑定相同处理
// 点击、鼠标移入打印*123*
$('#div1').on('click mouseenter', 123, function (e) {
console.log(e.data)
})
复制代码
3.2、 批量绑定不同处理
// 点击、鼠标移入、移出打印对应消息
$('#div1').on(
{
click: function (e) {console.log('点击:' + e.data)},
mouseenter: function (e) {console.log('鼠标进入:' + e.data)},
mouseleave: function (e) {console.log('鼠标移出!')}
},
123
)
复制代码
批量绑定不同处理,传入对象形式的参数,内部对参数进行了for...in解构,处理位置:
...
for ( type in types ) {
on( elem, type, selector, data, types[ type ], one );
}
...
复制代码
两种批量绑定事件最终都从on进入**add: function( elem, types, handler, data, selector ) **,在add方法进行最终的事件添加。 两者最终都会经过add方法的如下代码处理:
...
// Handle multiple events separated by a space
types = ( types || "" ).match( rnotwhite ) || [ "" ]; // types被转为数组,进入while循环遍历
t = types.length;
while ( t-- ) {
...
复制代码
4、 总结
虽然jquery内置了很多方便的处理,但还是有很多种情况考虑不到,比如下面这种情况就无法成功
$('#div1').on(['click', 'mouseenter'], function (e) {
console.log('点击了')
})
复制代码
所以,调用方法的时候还是按照约定好的数据结构来