深入分析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 相关文章推荐
理解Javascript_15_作用域分配与变量访问规则,再送个闭包
Oct 20 Javascript
javascript实现列表滚动的方法
Jul 30 Javascript
js匿名函数作为函数参数详解
Jun 01 Javascript
在点击div中的p时,如何阻止事件冒泡
Feb 07 Javascript
jQuery Ajax前后端使用JSON进行交互示例
Mar 17 Javascript
vue实现全选和反选功能
Aug 31 Javascript
security.js实现的RSA加密功能示例
Jun 06 Javascript
Angularjs中的$apply及优化使用详解
Jul 02 Javascript
vue-cli 引入jQuery,Bootstrap,popper的方法
Sep 03 jQuery
jQuery实现适用于移动端的跑马灯抽奖特效示例
Jan 18 jQuery
微信小程序开发实现的选项卡(窗口顶部/底部TabBar)页面切换功能图文详解
May 14 Javascript
关于layui导航栏不展示下拉列表的解决方法
Sep 25 Javascript
详解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读取csv文件内容的详解
2013/06/18 PHP
ThinkPHP中使用Ueditor富文本编辑器
2015/09/02 PHP
PHP5.3新特性小结
2016/02/14 PHP
深入分析PHP优化及注意事项
2016/07/04 PHP
javascript while语句和do while语句的区别分析
2007/12/08 Javascript
javascript框架设计读书笔记之种子模块
2014/12/02 Javascript
浅析JavaScript访问对象属性和方法及区别
2015/11/16 Javascript
浅谈jQuery为哪般去掉了浏览器检测
2016/08/29 Javascript
用jquery获取自定义的标签属性的值简单实例
2016/09/17 Javascript
原生JS+Canvas实现五子棋游戏实例
2017/06/19 Javascript
js实现数组内数据的上移和下移的实例
2017/11/14 Javascript
Node.js文件编码格式的转换的方法
2018/04/27 Javascript
angularjs实现的购物金额计算工具示例
2018/05/08 Javascript
js如何找出字符串中的最长回文串
2018/06/04 Javascript
记一次vue去除#问题处理经过小结
2019/01/24 Javascript
原生js实现商品筛选功能
2019/10/28 Javascript
vue 中的 render 函数作用详解
2020/02/28 Javascript
Vue自定义组件的四种方式示例详解
2020/02/28 Javascript
python 自动提交和抓取网页
2009/07/13 Python
python中文编码问题小结
2014/09/28 Python
python实现批量监控网站
2016/09/09 Python
python实现百万答题自动百度搜索答案
2018/01/16 Python
python获取url的返回信息方法
2018/12/17 Python
python实现可变变量名方法详解
2019/07/01 Python
python实现倒计时小工具
2019/07/29 Python
python twilio模块实现发送手机短信功能
2019/08/02 Python
Python打开文件、文件读写操作、with方式、文件常用函数实例分析
2020/01/07 Python
Pytorch保存模型用于测试和用于继续训练的区别详解
2020/01/10 Python
HTML5学习笔记之History API
2015/02/26 HTML / CSS
Burt’s Bees英国官网:世界领先的天然个人护理品牌
2020/08/17 全球购物
关于有小孩的离婚协议书
2014/10/26 职场文书
迎新晚会主持词开场白
2015/05/28 职场文书
积极心理学课程心得体会
2016/01/22 职场文书
经典格言警句:没有热忱,世间便无进步
2019/11/13 职场文书
python 三边测量定位的实现代码
2021/04/22 Python
动画电影《龙珠超 超级英雄》延期上映
2022/03/20 日漫