深入分析Javascript事件代理


Posted in Javascript onJanuary 30, 2016

很久很久以来,总感觉事件发生与事件代理到之间没什么鸟区别。

最近,又看了一下,感觉区别其实真不大!看怎么理解吧。

要搞清楚什么是事件代理,就需要先搞清楚什么是代理。

从商业角度来讲,代理就是:我有货,你没货,但丫我没时间、没精力全部卖掉,而你一天闲的蛋疼,只剩下时间了。于是,我委托你帮我买,然后哥给你提成。这个过程中,你实际上相当于也有了货。

OK,怎么从字面来理解事件代理一词的含义?后文有讲。

一 先看一个真实的,新手绑定onclik事件的例子

如果按照之前的我,我会怎么给每一个li标签,添加onlick呢?废话,要是我,肯定简单粗暴。
循环每一个li,然后全部绑定onlick。

于是我的代码应该是这样子:

<ul id="thl">
  <li>001</li>
  <li>002</li>
  <li>003</li>
</ul>

<script>
  var thl= document.getElementById('thl');
  var aLi = thl.getElementsByTagName('li');
  for (var i = 0; i < aLi.length; i++) {
  aLi[i].onclick = fn;
  }
  
  function fn (){
   console.log("maomaoliang");
  }
</script>

好像看起来没问题了。虽然,有些文章说这样很消耗性能,但是,我丫电脑好,老子管你性能,不能太认真。

二 突然有一天,我发现通过js添加进来的新的li,没有绑定onlcik

var node=document.createElement("li");
var textnode=document.createTextNode("maomaoliang");
node.appendChild(textnode);
document.getElementById("ul1").appendChild(node);

然后,点击maomaoliang,它并没有绑定我的onlick,这是为什么?
哦,原来,我原有的li跟我后面生成的li根本不是同时发生的,在创建新的li元素之前,已经给存在的li加事件了。好吧,好烦啊。

三 那怎么破?

然后,又好(无)奇(奈)的看了一些文章,原来有个叫事件代理的东西可以用。我就试试看吧!于是改写了部分代码,像这样:

var thl= document.getElementById('thl');
thl.onclick = function(ev) {
  ev = ev || event;
  //兼容处理
  var target = ev.target || ev.srcElement;
//找到li元素
  if (target.nodeName.toLowerCase() == 'li') {
     fn();
   }
};

function fn (){
 console.log("maomaoliang");
}

结果,点击新的li,居然也触发了fn函数。好吧,身为一个好奇心驱动的肉身,我怎么能不求甚解呢?还是要踏实点,搞清楚这其中的奥秘才行。

于是,看了事件代理的资料。

首先,要知道什么是事件冒泡:当一个元素上的事件被触发的时候,比如说鼠标点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。这一过程被称为事件冒泡。

然后,再回到之前的问题“怎么从字面来理解事件代理一词的含义”,谁代理了事件?或者事件代理了谁?
以本文的例子来讲,看看改动后的代码,我把onlick事件绑定到了ul标签上面,而不是li标签。于是,当我点击任何一个li标签(不管是动态生成的还是之前就有的)是,这个事件就像泡泡一样,冒啊冒。正常的情况下,ul也会绑定onclick,body也会绑定到onclick,也就说它会冒泡到最根层的元素。但我这里给ul绑定了onlick,那么这时,ul会把泡泡截住,事件也就停止上升,无法抵达body标签。

接着, var target = ev.target || ev.srcElement;这一句话,相当于告诉了我,我究竟点的是谁,谁才是target。如果,这个target刚刚好就是li标签if (target.nodeName.toLowerCase() == 'li'),那么执行fn函数。

最后,我骄傲的回答了那个问题:table代理了onlick事件!

四 回忆一下事件代理的步骤

父元素绑定事件
父元素知道事件的实际发生目标是谁
我们要对目标进行判断,如果是我们需要的元素,则发生回调函数(所以要学好选择器的使用)

五 最后总结,事件代理两大好处

性能不小心得到了优化
动态添加的元素也能绑定事件了

六 需要注意的一点是

上述针对的是原生js事件绑定来讲的,如果你用到了jquery。并把代码改成了如下的样子:

/*var thl= document.getElementById('ul1');
thl.onclick = function(ev) {
  ev = ev || event;
  //兼容处理
  var target = ev.target || ev.srcElement;
//找到li元素
  if (target.nodeName.toLowerCase() == 'li') {
     //li添加的事件
     fn();
   }
};*/

var node=document.createElement("li");
var textnode=document.createTextNode("maomaoliang");
node.appendChild(textnode);
document.getElementById("ul1").appendChild(node);

function fn (){
 console.log("maomaoliang");
}

$("#ul1").click(function(){
  fn();
});

这样一来,新添加的li标签,也能绑click,是不是很方便、很简单,是不是感觉学js没什么卵用。

哈哈,这样想很正常,我以前也这么想,但是,做了一些东西之后,发现jquery还真的不够用了!但是基本够用!

虽然,大神们都说要学js,但我还是觉得可以先学jquery,之后再学js,效果也可以的。

Javascript 相关文章推荐
ExtJS 2.0实用简明教程 之ExtJS版的Hello
Apr 29 Javascript
jQuery使用hide方法隐藏指定元素class样式用法实例
Mar 30 Javascript
javascript设计模式--策略模式之输入验证
Nov 27 Javascript
AngularJS控制器之间的通信方式详解
Nov 03 Javascript
vue.js 1.x与2.0中js实时监听input值的变化
Mar 15 Javascript
Bootstrap提示框效果的实例代码
Jul 12 Javascript
jQuery实现简单的计时器功能实例分析
Aug 29 jQuery
vue2.0 路由不显示router-view的解决方法
Mar 06 Javascript
在Angular中实现一个级联效果的下拉框的示例代码
May 20 Javascript
vue实现循环滚动列表
Jun 30 Javascript
JS pushlet XMLAdapter适配器用法案例解析
Oct 16 Javascript
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
May 25 Vue.js
详解javascript实现瀑布流列式布局
Jan 29 #Javascript
详解javascript实现瀑布流绝对式布局
Jan 29 #Javascript
理解Javascript文件动态加载
Jan 29 #Javascript
JavaScript操作select元素和option的实例代码
Jan 29 #Javascript
JavaScript学习总结之JS、AJAX应用
Jan 29 #Javascript
Angularjs中UI Router全攻略
Jan 29 #Javascript
JavaScript数据结构与算法之集合(Set)
Jan 29 #Javascript
You might like
php下载excel无法打开的解决方法
2013/12/24 PHP
php实现天干地支计算器示例
2014/03/14 PHP
php生成rss类用法实例
2015/04/14 PHP
PHP内核探索:哈希表碰撞攻击原理
2015/07/31 PHP
php使用preg_match()函数验证ip地址的方法
2017/01/07 PHP
利用PHP内置SERVER开启web服务(本地开发使用)
2021/03/09 PHP
HTML-CSS群中单选引发的“事件”
2007/03/05 Javascript
ExtJS 2.0 实用简明教程之布局概述
2009/04/29 Javascript
纯css+js写的一个简单的tab标签页带样式
2014/01/28 Javascript
Javascript 数组排序详解
2014/10/22 Javascript
详解Javascript 装载和执行
2014/11/17 Javascript
深入分析原生JavaScript事件
2014/12/29 Javascript
jQuery实现自定义右键菜单的树状菜单效果
2015/09/02 Javascript
jQuery easyUI datagrid 增加求和统计行的实现代码
2016/06/01 Javascript
关于前后端json数据的发送与接收详解
2017/07/30 Javascript
详解Nuxt.js中使用Element-UI填坑
2019/09/06 Javascript
node.js基础知识汇总
2020/08/25 Javascript
Ant Design moment对象和字符串之间的相互转化教程
2020/10/27 Javascript
[01:55]《走出家门看比赛》——DOTA2 2015国际邀请赛同城线下观战
2015/07/18 DOTA
跟老齐学Python之大话题小函数(1)
2014/10/10 Python
详解Django中的权限和组以及消息
2015/07/23 Python
详解python3中socket套接字的编码问题解决
2017/07/01 Python
python基础学习之如何对元组各个元素进行命名详解
2018/07/12 Python
Django框架中序列化和反序列化的例子
2019/08/06 Python
Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式
2020/01/10 Python
利用Tensorflow的队列多线程读取数据方式
2020/02/05 Python
耐克美国官网:Nike.com
2016/08/01 全球购物
Hunkemöller西班牙:欧洲最大的内衣连锁店
2018/08/15 全球购物
个人求职简历的自我评价
2013/10/19 职场文书
上班上网检讨书
2014/01/29 职场文书
村委会换届选举方案
2014/05/03 职场文书
领导干部对照检查材料
2014/08/24 职场文书
2014年信息宣传工作总结
2014/12/18 职场文书
基层组织建设年活动总结
2015/05/09 职场文书
个人催款函范文
2015/06/23 职场文书
优秀教师工作总结2015
2015/07/22 职场文书