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的表单操作 简单计算器
Dec 29 Javascript
JavaScript初学者建议:不要去管浏览器兼容
Feb 04 Javascript
减少访问DOM的次数提升javascript性能
Feb 24 Javascript
两种不同的方法实现js对checkbox进行全选和反选
May 13 Javascript
javascript判断并获取注册表中可信任站点的方法
Jun 01 Javascript
BootStrap中Datetimepicker和uploadify插件应用实例小结
May 26 Javascript
谈谈第三方App接入微信登录 解读
Dec 27 Javascript
JavaScript实现提交模式窗口后刷新父窗口数据的方法
Jun 16 Javascript
Javascript之高级数组API的使用实例
Mar 08 Javascript
vue + typescript + video.js实现 流媒体播放 视频监控功能
Jul 07 Javascript
JSONP 的原理、理解 与 实例分析
May 16 Javascript
vue实现Toast组件轻提示
Apr 10 Vue.js
个人总结的一些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 数组遍历方法大全(foreach,list,each)
2010/06/30 PHP
php中实现简单的ACL 完结篇
2011/09/07 PHP
PHP中如何使用session实现保存用户登录信息
2015/10/20 PHP
PHP常见漏洞攻击分析
2016/02/21 PHP
php实现微信发红包功能
2018/07/13 PHP
jQuery Ajax之load()方法
2009/10/12 Javascript
让你的CSS像Jquery一样做筛选的实现方法
2011/07/10 Javascript
JavaScript实现的一个计算数字步数的算法分享
2014/12/06 Javascript
JS选项卡动态替换banner图片路径的方法
2015/05/11 Javascript
完美实现js拖拽效果 return false用法详解
2017/07/28 Javascript
基于js中this和event 的区别(详解)
2017/10/24 Javascript
详解vue-cli 本地开发mock数据使用方法
2018/05/29 Javascript
解决bootstrap中下拉菜单点击后不关闭的问题
2018/08/10 Javascript
Bootbox将后台JSON数据填充Form表单的实例代码
2018/09/10 Javascript
详解Webpack如何引入CDN链接来优化编译后的体积
2019/06/21 Javascript
Vue 的双向绑定原理与用法揭秘
2020/05/06 Javascript
浅谈js数组splice删除某个元素爬坑
2020/10/14 Javascript
Vue中强制组件重新渲染的正确方法
2021/01/03 Vue.js
python操作redis的方法
2015/07/07 Python
Python random库使用方法及异常处理方案
2020/03/02 Python
keras 指定程序在某块卡上训练实例
2020/06/22 Python
python 批量将中文名转换为拼音
2021/02/07 Python
CSS3 制作绽放的莲花采用效果叠加实现
2013/01/31 HTML / CSS
英国最大的女性服装零售商:Dorothy Perkins
2017/03/30 全球购物
WiFi云数码相框:Nixplay
2018/07/05 全球购物
英国床垫和床架购物网站:Bedman
2019/11/04 全球购物
怎么写好自荐信
2013/10/30 职场文书
学生干部学习的自我评价
2014/02/18 职场文书
幼儿园八一建军节活动方案
2014/08/27 职场文书
党的群众路线教育实践活动批评与自我批评范文
2014/10/16 职场文书
邀请书格式范文
2015/02/02 职场文书
2016年元旦主持词
2015/07/06 职场文书
给校长的建议书作文500字
2015/09/14 职场文书
歌咏比赛口号大全
2015/12/25 职场文书
大学生党课心得体会
2016/01/07 职场文书
WINDOWS下安装mysql 8.x 的方法图文教程
2022/04/19 MySQL