javascript事件委托的方式绑定详解


Posted in Javascript onJune 10, 2015

js事件绑定

事件绑定,这里使用了冒泡的原理,从点击的元素开始,递归方式的向父元素传播事件,这样做的好处是对于大量要处理的元素,不必为每个元素都绑定事件,只需要在他们的父元素上绑定一次即可,提高性能。还有一个好处就是可以处理动态插入dom中的元素,直接绑定的方式是不行的。

之前一直使用的是jquery的on方法做这样的事情,前几天看到公司项目中有实现这种方式的源代码,拿来仔细研究研究,跟大家分享分享。

function $bindAction(dom, event, listeners) {
 #这里的dom为绑定事件的元素,比如document.body
 #event为绑定的事件,比如click
 #listeners是待执行的事件对象
 $addEvent(dom, event, function(e) {
 #这里获取事件e
 #获取点击的元素src
 var e = e || window.event,
  src = e.target || e.srcElement,
  action,
  returnVal;

 #模拟冒泡的方式,先是src,然后是src.parentNode,再然后是src.parentNode.parent.Node
 #当前dom元素等于事件绑定的dom元素的时候,停止“冒泡”
 while (src && src !== dom) {
  #循环获取dom元素的attr-action属性,
  action = src.getAttribute('attr-action');
  #如果当前dom元素存在attr-action属性,并且事件对象中有该属性值的函数,执行这个函数
  #将事件e、当前dom元素、元素的属性attr-action值传给要执行的函数
  if (listeners[action]) {
  returnVal = listeners[action]({
   src : src,
   e : e,
   action : action
  });
  #如果上面的函数执行之后返回false,停止继续“冒泡”
  if (returnVal === false) {
   break;
  }
  }
  #获取当前dom元素的父元素节点
  src = src.parentNode;
 }
 });
};

function $addEvent(obj, type, handle) {
 if(!obj || !type || !handle) {
 return;
 }
 #绑定事件到多个对象,递归调用
 if( obj instanceof Array) {
 for(var i = 0, l = obj.length; i < l; i++) {
  $addEvent(obj[i], type, handle);
 }
 return;
 }
 #绑定多个事件,递归调用
 if( type instanceof Array) {
 for(var i = 0, l = type.length; i < l; i++) {
  $addEvent(obj, type[i], handle);
 }
 return;
 }
 #下面这一大段用来记录当前页面一共绑定了多少个事件,以及事件的相关信息
 #以及某个对象上面绑定的事件id
 window.__allHandlers = window.__allHandlers || {};
 window.__Hcounter = window.__Hcounter || 0;
 function setHandler(obj, type, handler, wrapper) {
 obj.__hids = obj.__hids || [];
 var hid = 'h' + ++window.__Hcounter;
 obj.__hids.push(hid);
 window.__allHandlers[hid] = {
  type : type,
  handler : handler,
  wrapper : wrapper
 }
 }
 #这个里面的apply是为了修改绑定事件所执行函数中的this
 #这个在低版本的IE中才真正起作用
 function createDelegate(handle, context) {
 return function() {
  return handle.apply(context, arguments);
 };
 }

 #绑定事件,记录事件绑定信息
 if(window.addEventListener) {
 var wrapper = createDelegate(handle, obj);
 setHandler(obj, type, handle, wrapper)
 obj.addEventListener(type, wrapper, false);
 }
 else if(window.attachEvent) {
 var wrapper = createDelegate(handle, obj);
 setHandler(obj, type, handle, wrapper)
 obj.attachEvent("on" + type, wrapper);
 }
 else {
 obj["on" + type] = handle;
 }
};

看个例子:

当点击前三个的时候会依次弹出classname,其他的都不会触发事件

<style type="text/css">
#out{width: 500px;background-color: #CDE}
#inner{background-color: #ABCDEF;margin: 0;padding: 0;width: 400px;}
ul{background-color: pink;margin: 0;padding: 0;width: 400px;}
li{width:398px;height: 20px;border: 1px solid black;margin: 15px 0px;padding: 0px;list-style: none;}  
</style>
div#out > div#inner :
<div id="out">
 <ul id="inner">
 <li class="lia" attr-action="setWhat">class="lia" attr-action="setWhat"</li>
 <li class="lia" attr-action="setWhat">class="lia" attr-action="setWhat"</li>
 <li class="lib" attr-action="setWhat">class="lia" attr-action="setWhat"</li>
 <li class="lib">class="lib"</li>
 <li class="lib">class="lib"</li>
 <li class="lib">class="lib"</li>
 </ul>
</div>
ul :
<ul>
 <li class="lia" attr-action="setWhat">class="lia" attr-action="setWhat"</li>
 <li class="lia" attr-action="setWhat">class="lia" attr-action="setWhat"</li>
 <li class="lib" attr-action="setWhat">class="lia" attr-action="setWhat"</li>
 <li class="lib">class="lib"</li>
 <li class="lib">class="lib"</li>
 <li class="lib">class="lib"</li>
</ul>

<script>
listeners = {
 setWhat : function(opts) {
 alert(opts.src.className);
 return false;
 },
};
window.onload = function(){$bindAction(document.getElementById('out'), ['click', 'mouseover'], listeners);}
</script>

效果如下:

javascript事件委托的方式绑定详解

再看看事件的绑定情况,跟我们绑定事件的情况一致:

javascript事件委托的方式绑定详解

以上所述就是本文的全部内容了,希望大家能够喜欢。

Javascript 相关文章推荐
比较简单实用的使用正则三种版本的js去空格处理方法
Nov 18 Javascript
jquery复选框CHECKBOX全选、反选
Aug 30 Javascript
用jQuery打造TabPanel效果代码
May 22 Javascript
lyhucSelect基于Jquery的Select数据联动插件
Mar 29 Javascript
jquery next nextAll nextUntil siblings的区别介绍
Oct 05 Javascript
两种方法基于jQuery实现IE浏览器兼容placeholder效果
Oct 14 Javascript
vue2.0使用Sortable.js实现的拖拽功能示例
Feb 21 Javascript
jQuery插件ContextMenu自定义图标
Mar 15 Javascript
Vue2 模板template的四种写法总结
Feb 23 Javascript
js获取form表单中name属性的值
Feb 27 Javascript
a标签调用js的方法总结
Sep 05 Javascript
如何用JavaScript学习算法复杂度
Apr 30 Javascript
个人总结的一些JavaScript技巧、实用函数、简洁方法、编程细节
Jun 10 #Javascript
浅析JavaScript动画
Jun 10 #Javascript
JavaScript操作XML文件之XML读取方法
Jun 09 #Javascript
JavaScript检查数字是否为整数或浮点数的方法
Jun 09 #Javascript
jQuery取消ajax请求的方法
Jun 09 #Javascript
JavaScript动态添加style节点的方法
Jun 09 #Javascript
jQuery实现将页面上HTML标签换成另外标签的方法
Jun 09 #Javascript
You might like
php getsiteurl()函数
2009/09/05 PHP
第六章 php目录与文件操作
2011/12/30 PHP
调整PHP的性能
2013/10/30 PHP
php上传大文件失败的原因及应对策略
2015/10/20 PHP
php中文字符串截取多种方法汇总
2016/10/06 PHP
PHP之认识(二)关于Traits的用法详解
2019/04/11 PHP
jquery二级导航内容均分的原理及实现
2013/08/13 Javascript
详解JavaScript函数绑定
2013/08/18 Javascript
js 通用订单代码
2013/12/23 Javascript
在父页面得到zTree已选中的节点的方法
2015/02/12 Javascript
Javascript编程之继承实例汇总
2015/11/28 Javascript
javascript模块化简单解析
2016/04/07 Javascript
jQuery使用经验小技巧(推荐)
2016/05/31 Javascript
深入浅析JavaScript的API设计原则
2016/06/14 Javascript
jQuery插件passwordStrength密码强度指标详解
2016/06/24 Javascript
利用js来实现缩略语列表、文献来源链接和快捷键列表
2016/12/16 Javascript
AngularJS中filter的使用实例详解
2017/08/25 Javascript
微信web端后退强制刷新功能的实现代码
2018/03/04 Javascript
用ES6写全屏滚动插件的示例代码
2018/05/02 Javascript
vue element动态渲染、移除表单并添加验证的实现
2019/01/16 Javascript
今天,小程序正式支持 SVG
2019/04/20 Javascript
详解微信小程序获取当前时间及日期的方法
2019/04/28 Javascript
JS面向对象编程实现的Tab选项卡案例详解
2020/03/03 Javascript
python轻松查到删除自己的微信好友
2016/01/10 Python
python批量识别图片指定区域文字内容
2019/04/30 Python
python 实现矩阵按对角线打印
2019/11/29 Python
python pandas dataframe 去重函数的具体使用
2020/07/20 Python
建筑人员岗位职责
2013/12/25 职场文书
财务会计专业自荐书
2014/06/30 职场文书
岗位说明书怎么写
2014/07/30 职场文书
综合素质自我评价怎么写
2014/09/14 职场文书
道德模范事迹材料
2014/12/20 职场文书
后进生评语大全
2015/01/04 职场文书
义诊活动总结
2015/02/04 职场文书
遗失证明范文
2015/06/19 职场文书
为自由献出你的心脏!「进击的巨人展 FINAL」2022年6月在台开展
2022/04/13 日漫