深入分析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 相关文章推荐
dropdownlist之间的互相联动实现(显示与隐藏)
Nov 24 Javascript
jquery checkbox,radio是否选中的判断代码
Mar 20 Javascript
理解Javascript_05_原型继承原理
Oct 13 Javascript
js 判断上传文件大小及格式代码
Nov 13 Javascript
React.js入门实例教程之创建hello world 的5种方式
May 11 Javascript
jQuery+PHP实现微信转盘抽奖功能的方法
May 25 Javascript
对象不支持indexOf属性或方法的解决方法(必看)
May 28 Javascript
Bootstrap Table使用整理(二)
Jun 09 Javascript
慕课网题目之js实现抽奖系统功能
Sep 19 Javascript
jQuery实现右侧抽屉式在线客服功能
Dec 25 jQuery
vue中如何实现pdf文件预览的方法
Jul 12 Javascript
使用mixins实现elementUI表单全局验证的解决方法
Apr 02 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
关于使用key/value数据库redis和TTSERVER的心得体会
2013/06/28 PHP
Zend Framework教程之Zend_Config_Ini用法分析
2016/03/23 PHP
PHP实现的curl批量请求操作示例
2018/06/06 PHP
Gambit vs CL BO3 第三场 2.13
2021/03/10 DOTA
Javascript中的window.event.keyCode使用介绍
2011/04/26 Javascript
几种延迟加载JS代码的方法加快网页的访问速度
2013/10/12 Javascript
JS中使用Array函数shift和pop创建可忽略参数的例子
2014/05/28 Javascript
JS判断是否360安全浏览器极速内核的方法
2015/01/29 Javascript
javascript结合CSS实现苹果开关按钮特效
2015/04/07 Javascript
JS hashMap实例详解
2016/05/26 Javascript
jQuery实现radio第一次点击选中第二次点击取消功能
2017/05/15 jQuery
JS实现简单短信验证码界面
2017/08/07 Javascript
使用JavaScript实现点击循环切换图片效果
2017/09/03 Javascript
通过封装scroll.js 获取滚动条的值
2018/07/13 Javascript
Vue 菜单栏点击切换单个class(高亮)的方法
2018/08/22 Javascript
JS双向链表实现与使用方法示例(增加一个previous属性实现)
2019/01/31 Javascript
JavaScript setInterval()与setTimeout()计时器
2019/12/27 Javascript
Django1.7+python 2.78+pycharm配置mysql数据库教程
2014/11/18 Python
在Windows服务器下用Apache和mod_wsgi配置Python应用的教程
2015/05/06 Python
Python文件右键找不到IDLE打开项解决办法
2015/06/08 Python
Python的Django框架中设置日期和字段可选的方法
2015/07/17 Python
Python实现身份证号码解析
2015/09/01 Python
教你使用python实现微信每天给女朋友说晚安
2018/03/23 Python
python实现简单http服务器功能
2018/09/17 Python
在Pycharm中对代码进行注释和缩进的方法详解
2019/01/20 Python
基于django channel实现websocket的聊天室的方法示例
2019/04/11 Python
HTML5+CSS3实现无插件拖拽上传图片(支持预览与批量)
2017/01/05 HTML / CSS
HTML5 Canvas鼠标与键盘事件demo示例
2013/07/04 HTML / CSS
Chemist Warehouse官方海外旗舰店:澳洲第一连锁大药房
2017/08/25 全球购物
Sephora丝芙兰印尼官方网站:购买化妆品和护肤品
2018/07/02 全球购物
The Kooples美国官方网站:为情侣提供的法国当代时尚品牌
2019/01/03 全球购物
自荐信怎么写呢?
2013/12/09 职场文书
大班幼儿评语大全
2014/04/30 职场文书
综合实践活动报告
2015/02/05 职场文书
合同纠纷调解书
2015/05/20 职场文书
mysql定时自动备份数据库的方法步骤
2021/07/07 MySQL