JQuery实现click事件绑定与触发方法分析
原生JS通过什么方法绑定click事件?
原生js有一下三种方法为DOM对象绑定click事件,
第一种,在html中添加 onclick属性,在此属性中添加要绑定的事件函数,如下, 这种方法为html处理事件的原始方法,使得html和js过分耦合, 即表现层代码 和 行为层代码耦合:
<html>
<head>
<script src="./jquery.js"></script>
</head>
<body>
<div name="template">
<input type="button" name="testBtn" value="click me" onclick="sayHi()">
</div>
<script>
function sayHi()
{
alert("hi")
}
</script>
</body>
</html>
第二种方法, 在js中找到DOM对象, 为onclick属性动态绑定一个处理函数。 在html中不声明事件处理, 在js中定位到dom后动态执行click事件处理函数,如下, 好处是解耦, 修改dom的行为只需要修改一处js代码即可:
<html>
<head>
<script src="./jquery.js"></script>
</head>
<body>
<div name="template">
<input type="button" id="testBtn" value="click me">
</div>
<script>
function sayHi()
{
alert("hi")
}
document.getElementById("testBtn").onclick=sayHi;
</script>
</body>
</html>
第三种方法, 是使用通用的事件绑定函数, 将一个事件动态绑定处理函数,如下,这种方法可以自定义事件, 并配合dispatchEvent可以使得事件冒泡(https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events):
<html>
<head>
<script src="./jquery.js"></script>
</head>
<body>
<div name="template">
<input type="button" id="testBtn" value="click me">
</div>
<script>
function sayHi()
{
alert("hi")
}
document.getElementById("testBtn").addEventListener("click",sayHi);
</script>
</body>
</html>
JQuery click 实现分析
jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) { // Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
return arguments.length > 0 ?
this.on( name, null, data, fn ) :
this.trigger( name );
};
});
首先, click作为JQuery对象的方法, 实际上集成其原型对象的方法fn集合, 其中有一个函数名称叫 click,
当click函数调用没有参数,表示触发此事件,对应this.trigger( name ),
当click参数为函数,则将此函数绑定到此对象的click事件上, 对应了 this.on( name, null, data, fn )。
其次,分析下 this.on的实现:
对于click绑定一个事件处理函数的情况, 相关代码:
jQuery.fn.extend({ on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
var type, origFn;
。。。
return this.each( function() {
jQuery.event.add( this, types, fn, data, selector );
});
},
on绑定是调用 jQuery.event.add 实现,
下面分析 jQuery.event.add 对于 click绑定一个函数的实现情况。
解释入下面代码注释, 当事件发生, 会触发 公共事件处理函数 elemData.handle, 在此函数中, 会将当前的事件调用dispatch函数,分发到对应的elem对象上。
总结下:
(1) on的实现通过jquery.event.add, 将事件公用处理函数elemData.handle,通过addEventListener绑定到具体的事件类型上,
(2)并将待触发的函数, 存储于 handlers == elemData.events[type]
jQuery.event = { global: {}, add: function( elem, types, handler, data, selector ) {
var tmp, events, t, handleObjIn,
special, eventHandle, handleObj,
handlers, type, namespaces, origType,
elemData = jQuery._data( elem );
。。。。
// 给每一个需要绑定的事件处理函数,定义一个唯一的ID
// Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
//定义事件集合,存储于 elem -》data的 events 对象中
// Init the element's event structure and main handler, if this is the first
if ( !(events = elemData.events) ) {
events = elemData.events = {};
}
// 定义elem对象的 事件处理函数, 存储于elem-》data的 handle成员中, 为一个函数
if ( !(eventHandle = elemData.handle) ) {
eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== strundefined && (!e || jQuery.event.triggered !== e.type) ?
jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :
undefined;
};
// Add elem as a property of the handle fn to prevent a memory leak with IE non-native events
eventHandle.elem = elem;
}
。。。。。。
// Init the event handler queue if we're the first
if ( !(handlers = events[ type ]) ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0; // 将定义的事件处理函数, 绑定到具体的事件类型
// Only use addEventListener/attachEvent if the special events handler returns false
if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
// Bind the global event handler to the element
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle, false ); } else if ( elem.attachEvent ) {
elem.attachEvent( "on" + type, eventHandle );
}
}
}
。。。。。
// 将待绑定的click参数(响应函数)存储到handlers中, handlers == elemData.events[type]
// Add to the element's handler list, delegates in front
if ( selector ) {
handlers.splice( handlers.delegateCount++, 0, handleObj );
} else {
handlers.push( handleObj );
}
下面看下trigger事件函数如何执行?
将按照事件名,构建冒泡路径, 依次冒泡执行 addEventListener绑定的事件公共处理函数。
trigger: function( event, data, elem, onlyHandlers ) {
。。。。。。
// 按照DOM树向上构造 冒泡 路径
for ( ; cur; cur = cur.parentNode ) {
eventPath.push( cur );
tmp = cur;
}
..................
// jQuery handler
handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && jQuery._data( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
} // Native handler
handle = ontype && cur[ ontype ];
if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
event.result = handle.apply( cur, data );
if ( event.result === false ) {
event.preventDefault();
}
}
此函数(elemData.handle)中会调用dispatch,将所有的handlers中相同类型事件调用一遍
下面是dispatch的关键代码。
dispatch: function( event ) {
handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [],
。。。。。。
// Determine handlers
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
,,,,,
while ( (handleObj = matched.handlers[ j++ ]) && !event.
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
.apply( matched.elem, args );
。。。。。。。
实现思路-描述代码:
给事件绑定公共函数,
将注册事件函数存储到数组中,
公共函数中,对数组中的注册函数依次调用。
<html>
<head>
<script src="./jquery.js"></script>
</head>
<body>
<div name="template">
<input type="button" id="testBtn" value="click me">
</div>
<script>
/* core code start */
var eventHandlers = [];
function clickHandle()
{
//触发每个绑定函数
for (var i in eventHandlers)
{
eventHandlers[i]();
}
}
function addHandle(fn)
{
eventHandlers.push(fn);
}
/* core code end */ //绑定函数1 绑定
function sayHi()
{
alert("hi");
}
addHandle(sayHi); //绑定函数2 绑定
function sayHello()
{
alert("hello");
}
addHandle(sayHello); //绑定公共处理函数
document.getElementById("testBtn").addEventListener("click",clickHandle); //脚本 - 触发公共处理函数
var clickfn = document.getElementById("testBtn")["click"];
console.log(clickfn)
clickfn.apply(document.getElementById("testBtn"))
</script>
</body>
</html>
JQuery实现click事件绑定与触发方法分析的更多相关文章
- jQuery中click事件多次触发解决方案
jQuery 中元素的click事件中绑定其他元素的click事件. 因为jQuery中的click事件会累计绑定,导致事件注册越来越多. 解决方案: 1.能够避开,避免把click事件绑定到其他元素 ...
- jquery移除、绑定、触发元素事件使用示例详解
这篇文章主要介绍了jquery移除.绑定.触发元素事件使用示例详解,需要的朋友可以参考下. unbind(type [,data]) //data是要移除的函数 $('#btn').unbind(&q ...
- jQuery的事件绑定与触发 - 学习笔记
jQuery的事件绑定与触发 事件绑定 自动触发事件 常用的鼠标事件 事件冒泡和默认行为 事件冒泡 默认行为 获得当前鼠标的位置和按键 jQuery的事件绑定与触发 事件绑定 基本绑定 $(eleme ...
- jQuery中的事件绑定方法
在jQuery中,事件绑定方法大致有四种:bind(),live(), delegate(),和on(). 那么在工作中应该如何选择呢?首先要了解四种方法的区别和各自的特点. 在了解这些之前,首先要知 ...
- Jquery中的事件绑定$("#btn").bind("click",function(){ })
Jquery中的事件绑定:$("#btn").bind("click",function(){ }) 由于每次都这么调用太麻烦,所以jquery就用$(&qu ...
- click事件多次触发 jQuery
jQuery 中 click事件会累计绑定 例如下列代码: aNode.click(function(){ bNode.click(function(){ console.log('haha'); } ...
- 关于jQuery新的事件绑定机制on()的使用技巧
关于jQuery新的事件绑定机制on()的使用技巧 http://www.jb51.net/article/36064.htm 本篇文章介绍了,关于jQuery新的事件绑定机制on()的使用技巧.需要 ...
- jQuery三种事件绑定方式.bind(),.live(),.delegate()
.bind(), .live(), 和 .delegate()之间的区别并不明显.但是理解它们的不同之处有助于写出更简洁的代码,并防止我们的交互程序中出现没有预料到的bug. 基础 DOM树 首先,图 ...
- jQuery 中的事件绑定
一.事件概念 和数据库中的触发器一样,当操作了数据的时候会引发对应的触发器程序执行 一样,JS 中的事件就是对用户特定的行为作出相应的响应的过程,其实上就是浏览器 监听到用户的某些行为的时候会执行对应 ...
随机推荐
- Nginx学习回顾总结 部分:
21:46 2015/11/9Nginx学习回顾总结进程间通信,近似于socket通信的的东西:才发现这种通信并不是很难,并不是我想象的那样很多内容,新领域,入门只是几个函数的使用而已.以前猜过是这样 ...
- 【BZOJ】1124: [POI2008]枪战Maf
题意 \(n(n < 1000000)\)个人,每个人\(i\)指向一个人\(p_i\),如果轮到\(i\)了且他没死,则他会将\(p_i\)打死.求一种顺序,问死的人最少和最多的数目. 分析 ...
- 【BZOJ1257】【CQOI2007】余数之和sum
Description 给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数.例如j(5, ...
- This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release.
一,经历 <1> 使用SDWebImage下载 成功图片后,将图片设置给 self.imageView.image,提示如题所示的错误提示. <2>第一反应就是慢慢注释掉代码进 ...
- UVA 558 判定负环,spfa模板题
1.UVA 558 Wormholes 2.总结:第一个spfa,好气的是用next[]数组判定Compilation error,改成nexte[]就过了..难道next还是特殊词吗 题意:科学家, ...
- XCode编译文件过多导致内存吃紧解决方法
XCode编译文件过多导致内存吃紧解决方法 /Users/~~/Library/Developer/Xcode/DerivedData 1) 然后 找到编译文件 删除 就好了哦 快去试试看吧
- POI Word 模板 文字 图片 替换
实验环境:POI3.7+Word2007 Word模板: 替换后效果: 代码: 1.入口文件 public class Test { public static void main(String[] ...
- Hibernate框架配置
API package com.hanqi.test; import static org.junit.Assert.*; import org.hibernate.SessionFactory; ...
- LabVIEW如何将脚本插入Quick Drop
问题:如何将自己设计的LabVIEW脚本做成快捷键的方式,实现效果如下 解决: 第一步:在LabVIEW Data中新建Quick Drop Plugins 第二步 在文件夹下新建一个VI,VI接口的 ...
- tab1
<html> <head> <meta charset="UTF-8"> <title>tab</title> < ...