深入分析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 TabPanel beforeremove beforeclose使用说明
Mar 31 Javascript
jquery动态添加删除一行数据示例
Jun 12 Javascript
js鼠标点击图片切换效果实现代码
Nov 19 Javascript
详解vue-cli + webpack 多页面实例应用
Apr 25 Javascript
利用Node.js检测端口是否被占用的方法
Dec 07 Javascript
JavaScript面向对象继承原理与实现方法分析
Aug 09 Javascript
vue 刷新之后 嵌套路由不变 重新渲染页面的方法
Sep 13 Javascript
AngularJS 监听变量变化的实现方法
Oct 09 Javascript
如何使用electron-builder及electron-updater给项目配置自动更新
Dec 24 Javascript
微信小程序仿今日头条导航栏滚动解析
Aug 20 Javascript
JavaScript eval()函数定义及使用方法详解
Jul 07 Javascript
javascript函数式编程基础
Sep 15 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 使用array函数实现分页
2015/02/13 PHP
yii2.0框架多模型操作示例【添加/修改/删除】
2020/04/13 PHP
jQuery 页面载入进度条实现代码
2009/02/08 Javascript
JavaScript的eval JSON object问题
2009/11/15 Javascript
图片轮换效果实现代码(点击按钮停止执行)
2013/04/12 Javascript
js验证整数加保留小数点的简单实例
2013/12/02 Javascript
Jquery弹出层插件ThickBox的使用方法
2014/12/09 Javascript
javascript创建函数的20种方式汇总
2015/06/23 Javascript
javascript高级选择器querySelector和querySelectorAll全面解析
2016/04/07 Javascript
浅谈JS中的bind方法与函数柯里化
2016/08/10 Javascript
详解用原生JavaScript实现jQuery的某些简单功能
2016/12/19 Javascript
详解使用vue-router进行页面切换时滚动条位置与滚动监听事件
2017/03/08 Javascript
详解Angular 开发环境搭建
2017/06/22 Javascript
SVG动画vivus.js库使用小结(实例代码)
2017/09/14 Javascript
使用原生js+canvas实现模拟心电图的实例
2017/09/20 Javascript
利用jqprint插件打印页面内容的实现方法
2018/01/09 Javascript
详解基于vue-cli3.0如何构建功能完善的前端架子
2018/10/09 Javascript
JavaScript实现小球沿正弦曲线运动
2020/09/07 Javascript
解决微信小程序云开发中获取数据库的内容为空的方法
2019/05/15 Javascript
JS实现4位随机验证码
2020/10/19 Javascript
python爬虫教程之爬取百度贴吧并下载的示例
2014/03/07 Python
Django中模型Model添加JSON类型字段的方法
2015/06/17 Python
Python之os操作方法(详解)
2017/06/15 Python
Python使用matplotlib绘制多个图形单独显示的方法示例
2018/03/14 Python
python 重定向获取真实url的方法
2018/05/11 Python
Python3列表内置方法大全及示例代码小结
2019/05/10 Python
python3读取csv文件任意行列代码实例
2020/01/13 Python
Sentry错误日志监控使用方法解析
2020/11/12 Python
整理HTML5的一些新特性与Canvas的常用属性
2016/01/29 HTML / CSS
王力宏牛津大学演讲稿
2014/05/22 职场文书
关心下一代工作先进事迹
2014/08/15 职场文书
大学团日活动新闻稿
2014/09/10 职场文书
试用期辞职信范文
2015/03/02 职场文书
golang如何去除多余空白字符(含制表符)
2021/04/25 Golang
nodejs利用readline提示输入内容实例代码
2021/07/15 NodeJs
彩虹社八名人气艺人全新周边限时推出,性转女装男装一次拥有!
2022/04/01 日漫