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 相关文章推荐
基于jQuery的星级评分插件
Aug 12 Javascript
深入浅出分析javaScript中this用法
May 09 Javascript
基于Jquery实现焦点图淡出淡入效果
Nov 30 Javascript
JavaScript html5 canvas绘制时钟效果
Mar 01 Javascript
再次谈论React.js实现原生js拖拽效果引起的一系列问题
Apr 03 Javascript
关于JS Lodop打印插件打印Bootstrap样式错乱问题的解决方案
Dec 23 Javascript
从零开始学习Node.js系列教程六:EventEmitter发送和接收事件的方法示例
Apr 13 Javascript
说说AngularJS中的$parse和$eval的用法
Sep 14 Javascript
js技巧之十几行的代码实现vue.watch代码
Jun 09 Javascript
vue回到顶部监听滚动事件详解
Aug 02 Javascript
JavaScript观察者模式原理与用法实例详解
Mar 10 Javascript
Vue实现简单计算器
Jan 20 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 simple_html_dom.php+正则 采集文章代码
2009/12/24 PHP
php支付宝接口用法分析
2015/01/04 PHP
使用laravel指定日志文件记录任意日志
2019/10/17 PHP
JS写的数字拼图小游戏代码[学习参考]
2008/10/29 Javascript
js中有关IE版本检测
2012/01/04 Javascript
如何使用json在前后台进行数据传输实例介绍
2013/04/11 Javascript
js处理表格对table进行修饰
2014/05/26 Javascript
JavaScript实现基于十进制的四舍五入实例
2015/07/17 Javascript
jQuery采用连缀写法实现的折叠菜单效果
2015/09/18 Javascript
AngularJS初始化静态模板详解
2016/01/14 Javascript
基于JS实现新闻列表无缝向上滚动实例代码
2016/01/22 Javascript
Angular实现购物车计算示例代码
2017/02/21 Javascript
Vue基本指令实例图文讲解
2021/02/25 Vue.js
[01:44]剑指西雅图 展望TI之CIS战队专访
2014/06/25 DOTA
python抓取某汽车网数据解析html存入excel示例
2013/12/04 Python
python代码制作configure文件示例
2014/07/28 Python
python生成器generator用法实例分析
2015/06/04 Python
一步步教你用Python实现2048小游戏
2017/01/19 Python
只需7行Python代码玩转微信自动聊天
2019/01/27 Python
用python 实现在不确定行数情况下多行输入方法
2019/01/28 Python
详解Python传入参数的几种方法
2019/05/16 Python
python调用webservice接口的实现
2019/07/12 Python
tensorflow如何批量读取图片
2019/08/29 Python
用Python画一个LinkinPark的logo代码实例
2019/09/10 Python
酒吧总经理岗位职责
2013/12/10 职场文书
银行学习十八大感想
2014/01/11 职场文书
学校搬迁方案
2014/06/15 职场文书
服装设计专业求职信
2014/06/16 职场文书
篮球社团活动总结
2014/06/27 职场文书
食品安全承诺书范文
2014/08/29 职场文书
党委领导班子整改方案
2014/09/30 职场文书
毕业纪念册寄语大全
2015/02/26 职场文书
党小组鉴定意见
2015/06/02 职场文书
2016应届大学生自荐信模板
2016/01/28 职场文书
Nginx同一个域名配置多个项目的实现方法
2021/03/31 Servers
fastdfs+nginx集群搭建的实现
2021/03/31 Servers