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 07 Javascript
js正确获取元素样式详解
Aug 07 Javascript
JavaScript 直接操作本地文件的实现代码
Dec 01 Javascript
让ie运行js时提示允许阻止内容运行的解决方法
Oct 24 Javascript
JS判断不能为空实例代码
Nov 26 Javascript
JS动态改变浏览器标题的方法
Apr 06 Javascript
全面解析Bootstrap中tab(选项卡)的使用方法
Jun 06 Javascript
使用clipboard.js实现复制功能的示例代码
Oct 16 Javascript
ES6扩展运算符用法实例分析
Oct 31 Javascript
vue中引用阿里字体图标的方法
Feb 10 Javascript
VUE中使用HTTP库Axios方法详解
Feb 05 Javascript
js实现列表按字母排序
Aug 11 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
Terran兵种介绍
2020/03/14 星际争霸
PHP校验ISBN码的函数代码
2011/01/17 PHP
php网上商城购物车设计代码分享
2012/02/15 PHP
php生成微信红包数组的方法
2019/09/05 PHP
让焦点自动跳转
2006/07/01 Javascript
javascript使用eval或者new Function进行语法检查
2010/10/16 Javascript
通过js获取上传的图片信息(临时保存路径,名称,大小)然后通过ajax传递给后端的方法
2015/10/01 Javascript
论JavaScript模块化编程
2016/03/07 Javascript
AngularJS基础 ng-selected 指令简单示例
2016/08/03 Javascript
JS弹出窗口的运用与技巧大全
2016/11/01 Javascript
微信小程序中使元素占满整个屏幕高度实现方法
2016/12/14 Javascript
JavaScript实现汉字转换为拼音的库文件示例
2016/12/22 Javascript
vue.js异步上传文件前后端实现代码
2017/08/22 Javascript
layui自己添加图片按钮并点击跳转页面的例子
2019/09/14 Javascript
在layui框架中select下拉框监听更改事件的例子
2019/09/20 Javascript
使用zrender.js绘制体温单效果
2019/10/31 Javascript
Vue export import 导入导出的多种方式与区别介绍
2020/02/12 Javascript
vue 验证两次输入的密码是否一致的方法示例
2020/09/29 Javascript
[02:26]2016国际邀请赛8月3日开战 中国军团出征西雅图
2016/08/02 DOTA
Python使用pymysql小技巧
2017/06/04 Python
老生常谈python的私有公有属性(必看篇)
2017/06/09 Python
pip安装时ReadTimeoutError的解决方法
2018/06/12 Python
django+echart绘制曲线图的方法示例
2018/11/26 Python
tensorflow如何批量读取图片
2019/08/29 Python
Pandas实现DataFrame按行求百分数(比例数)
2019/12/27 Python
用python拟合等角螺线的实现示例
2019/12/27 Python
Python使用多进程运行含有任意个参数的函数
2020/05/02 Python
师范应届生语文教师求职信
2013/10/29 职场文书
竞争性谈判邀请书
2014/02/06 职场文书
《泉水》教学反思
2014/04/11 职场文书
迎新晚会策划方案
2014/06/13 职场文书
教师年度个人总结
2015/02/11 职场文书
初中毕业生自我评价
2015/03/02 职场文书
教师自荐信范文
2015/03/06 职场文书
队列队形口号
2015/12/25 职场文书
PYTHON InceptionV3模型的复现详解
2022/05/06 Python