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 相关文章推荐
javascript 一个函数对同一元素的多个事件响应
Jul 25 Javascript
ExtJS下grid的一些属性说明
Dec 13 Javascript
javascript中字符串替换函数replace()方法与c# 、vb 替换有一点不同
Jun 25 Javascript
用js判断页面是否加载完成实现代码
Dec 11 Javascript
javascrip关于继承的小例子
May 10 Javascript
JavaScript中模拟实现jsonp
Jun 19 Javascript
简单封装js的dom查询实例代码
Jul 08 Javascript
ros::spin() 和 ros::spinOnce()函数的区别及详解
Oct 01 Javascript
javascript 动态生成css代码的两种方法
Mar 17 Javascript
基于BootStrap实现简洁注册界面
Jul 20 Javascript
vue-cli配置全局sass、less变量的方法
Jun 06 Javascript
基于Vue el-autocomplete 实现类似百度搜索框功能
Oct 25 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
日本十大惊悚动漫
2020/03/04 日漫
PHP动态创建Web站点的方法
2011/08/14 PHP
ThinkPHP 3.2 数据分页代码分享
2014/10/14 PHP
PHP实现163邮箱自动发送邮件
2016/03/29 PHP
js加载之使用DOM方法动态加载Javascript文件
2013/11/08 Javascript
简单的两种Extjs formpanel加载数据的方式
2013/11/09 Javascript
使用JQuery快速实现Tab的AJAX动态载入(实例讲解)
2013/12/11 Javascript
jQuery照片伸缩效果不影响其他元素的布局
2014/05/09 Javascript
简单的jquery左侧导航栏和页面选中效果
2014/08/21 Javascript
jQuery插件bxSlider实现响应式焦点图
2015/04/12 Javascript
iPhone手机上搭建nodejs服务器步骤方法
2015/07/06 NodeJs
js实现兼容IE、Firefox的图片缩放代码
2015/12/08 Javascript
学习JavaScript事件流和事件处理程序
2016/01/25 Javascript
smartupload实现文件上传时获取表单数据(推荐)
2016/12/12 Javascript
JavaScript实现的鼠标响应颜色渐变效果完整实例
2017/02/18 Javascript
js编写选项卡效果
2017/05/23 Javascript
Vue关于组件化开发知识点详解
2020/05/13 Javascript
vue-i18n实现中英文切换的方法
2020/07/06 Javascript
[03:20]2015国际邀请赛全明星表演赛
2015/08/08 DOTA
使用Python操作MySQL的一些基本方法
2015/08/16 Python
python之消除前缀重命名的方法
2018/10/21 Python
在python中实现强制关闭线程的示例
2019/01/22 Python
django框架用户权限中的session缓存到redis中的方法
2019/08/06 Python
python 删除excel表格重复行,数据预处理操作
2020/07/06 Python
python实现一个简单RPC框架的示例
2020/10/28 Python
Regatta官网:英国最受欢迎的户外服装和鞋类品牌
2019/05/01 全球购物
麦当劳印度网上订餐:McDelivery
2020/03/16 全球购物
Cocopanda波兰:购买化妆品、护肤品、护发和香水
2020/05/25 全球购物
教育局长自荐信范文
2013/12/22 职场文书
就业协议书怎么填
2014/04/11 职场文书
2014年百日安全生产活动总结
2014/05/04 职场文书
司法局群众路线教育实践活动整改措施
2014/09/17 职场文书
行政处罚事先告知书
2015/07/01 职场文书
2015年教师个人业务工作总结
2015/10/23 职场文书
python读取pdf格式文档的实现代码
2021/04/01 Python
pytorch实现手写数字图片识别
2021/05/20 Python