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获得CheckBoxList选中的数量
Oct 27 Javascript
用jquery实现学校的校历(asp.net+jquery ui 1.72)
Jan 01 Javascript
AJAX使用了UpdatePanel后无法使用alert弹出脚本
Apr 02 Javascript
jQuery 源码分析笔记(2) 变量列表
May 28 Javascript
jquery与js函数冲突的两种解决方法
Sep 09 Javascript
使用jQuery在对象中缓存选择器的简单方法
Jun 30 Javascript
正则表达式,替换所有HTML标签的简单实例
Nov 28 Javascript
Angular 2.x学习教程之结构指令详解
May 25 Javascript
基于LayUI分页和LayUI laypage分页的使用示例
Aug 02 Javascript
JavaScript实现的贝塞尔曲线算法简单示例
Jan 30 Javascript
JS删除数组里的某个元素方法
Feb 03 Javascript
vue的mixins属性详解
Mar 14 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
smarty模板中使用get、post、request、cookies、session变量的方法
2014/04/24 PHP
ThinkPHP结合ajax、Mysql实现的客户端通信功能代码示例
2014/06/23 PHP
PHP使用静态方法的几个注意事项
2014/09/16 PHP
Zend Framework处理Json数据方法详解
2016/12/09 PHP
DOM 基本方法
2009/07/18 Javascript
js截取函数(indexOf,join等)
2010/09/01 Javascript
js获取某月的最后一天日期的简单实例
2013/06/22 Javascript
html的DOM中Event对象onabort事件用法实例
2015/01/21 Javascript
js判断子窗体是否关闭的方法
2015/08/11 Javascript
jquery实现图片预加载
2015/12/25 Javascript
Javascript如何判断数据类型和数组类型
2016/06/22 Javascript
jQuery获取file控件中图片的宽高与大小
2016/08/04 Javascript
jquery表单提交带错误信息提示效果
2017/03/09 Javascript
jQuery插件FusionCharts实现的Marimekko图效果示例【附demo源码】
2017/03/24 jQuery
Webpack打包css后z-index被重新计算的解决方法
2017/06/18 Javascript
vue.js使用v-if实现显示与隐藏功能示例
2018/07/06 Javascript
vue项目打包部署到服务器的方法示例
2018/08/27 Javascript
layui数据表格重载实现往后台传参
2019/11/15 Javascript
JavaScript实现PC端四格密码输入框功能
2020/02/19 Javascript
[01:46]新英雄登场
2019/09/10 DOTA
python字符串替换第一个字符串的方法
2019/06/26 Python
使用Pyinstaller转换.py文件为.exe可执行程序过程详解
2019/08/06 Python
python将字典列表导出为Excel文件的方法
2019/09/02 Python
windows下Python安装、使用教程和Notepad++的使用教程
2019/10/06 Python
Python用类实现扑克牌发牌的示例代码
2020/06/01 Python
python 制作网站小说下载器
2021/02/20 Python
使用纯 CSS 创作一个脉动 loader效果的源码
2018/09/28 HTML / CSS
WoolOvers爱尔兰:羊绒、羊毛和棉针织品
2017/01/04 全球购物
顶岗实习接收函
2014/01/09 职场文书
优秀经理事迹材料
2014/02/01 职场文书
2014年学校党建工作汇报材料
2014/11/02 职场文书
武侯祠导游词
2015/02/04 职场文书
女方家长婚礼答谢词
2015/09/29 职场文书
python爬取新闻门户网站的示例
2021/04/25 Python
使用Golang的channel交叉打印两个数组的操作
2021/04/29 Golang
windows server 2016 域环境搭建的方法步骤(图文)
2022/06/25 Servers