打算封装一个弹窗组件,作的时候忘记了考虑事件冒泡的因素,结果被坑得不要不要的。为了解决本身的问题,去查阅了很多资料,把事件流相关的知识都给总结一下。css
事件冒泡:一个简单,可是坑了我无数回的知识点!html
JavaScript与HTML的交互经过事件来实现。而浏览器的事件流是一个很是重要的概念。不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议,只须要知道在DOM2中规定的事件流包括了三个部分,事件捕获阶段、处于目标阶段、事件冒泡阶段。jquery
事件捕获,是从document元素开始,越高级的父级元素越早接收到事件,所以这是一个从上而下的过程。git
仍是那句话,没在实际应用中踩过坑,可能你真的不算掌握了这个知识点。那么,事件捕获有什么常见的坑呢?github
可能很多同窗在初学js的时候遇到过这样一个坑。一个ul元素中初始的状态有4个li元素,咱们能够循环给li元素添加click事件,执行咱们想要的动做。这个例子的坑就在于,新添加的li元素不会有咱们绑定的click事件。浏览器
<ul class="container"> <!-- 先循环给原有的4个li绑定click事件 --> <li class="item"></li> <li class="item"></li> <li class="item"></li> <li class="item"></li> <!-- 这是新添加的li元素,可是该元素没绑定click事件 --> <li class="item new"></li> </ul>
是的,就是这么坑,为了解决这个问题,咱们就要利用事件捕获的原理。spa
$('ul.container').click(function(event) { var target = event.target; if (target.className == 'item') { // dosomething } })
在上面的解决方案中,我并非直接给li绑定事件,而是给全部li的父级ul绑定事件。根据事件捕获的原理,事件会自上而下传递给li,咱们只须要经过一些简单的条件判断来肯定咱们的目标元素便可,如上例中的判断li的className。code
这个方式就是大名鼎鼎的事件委托。htm
事件委托是一个很重要并且在实际中会经常用到的知识点。事件
当咱们在使用className判断目标元素时,会遇到这样的状况。
... <li class="item"> <div class="title">xxx</title> <p class="desc">xxxxxxs</p> </li> ...
当咱们试图使用事件委托但愿给全部的li添加元素时,在利用className判断的过程当中发现,目标event.target元素竟然是li.item的子元素,这个时候就没办法准确的将事件绑定到li上了,这个时候咱们应该怎么办?
这种状况,咱们要作的,就是阻止事件捕获的传递,那么,要如何阻止呢?
我知道的一种方式,利用css,给li全部子元素添加以下css属性便可
li.item > * { pointer-events: none; }
按道理来讲,应该是有js方式的,但是查了不少文章都没有说起,所以就暂时这样吧,到时候遇到了在补充。
在jquery中,已经帮助咱们实现了事件委托,而且帮咱们解决掉了这些坑。咱们只须要按照必定语法使用便可,而咱们不用再本身去进行条件判断,好比咱们要给全部的li.item元素绑定事件,写法以下
// on中的第二参数就是咱们的目标元素的选择器 $('ul.container').on('click', 'li.item', function(event) { // dosomething })
说完了事件捕获,而后来讲说事件冒泡这个坑。所谓事件冒泡,就是让DOM树最底层的目标元素最早接收到事件,而后往上传递,这是一个自下而上的过程。
咱们经常会遇到一种弹窗样式,弹窗出来时,内容在中间,而后会有一层半透明的遮罩将页面内容与弹窗区分开。弹窗内容会有一些按钮绑定点击事件,好比确认与取消。而在半透明遮罩上,可能也会绑定一个点击事件,当点击时,将弹窗隐藏。若是我因为经验不足,将该遮罩层设置成了弹窗按钮的父级,那么就会遇到事件冒泡带来的麻烦。
也就是说,在以下例子中 container是全屏遮罩,button是弹窗里面的点击按钮。他们都同时绑定了click事件,执行不一样的动做。可是在实际执行的时候,当我点击了button,那么button和container的click事件都会执行,自下而上按顺序执行
<div className="container"> <div className="button">click</div> </div>
我为这个事情写了一个小例子,你们能够动手感觉一下这个坑。点击空白会生成一个弹窗
http://yangbo5207.github.io/s...
好吧解决问题的方法很简单,就是阻止冒泡事件。
$xxx.click(function(e) { e.stopPropagation(); // ie e.cancelBubble = true; })
理解了整个事件流,咱们能够感觉事件在DOM中的传递过程与方向,而且利用他来解决咱们的问题和各类坑,虽然是一个简单的知识点,可是却很是容易被忽略,所以建议你们找机会将它掌握牢固。
而还有一个坑,可能你们在实际中会不多遇到,这个坑就是,某些事件类型天生就不支持事件冒泡!
blur: 在元素失去焦点时触发,该事件不支持冒泡
focus: 在元素得到焦点时触发,该事件不支持冒泡
mouseenter: 当鼠标移入元素时触发,该事件不支持冒泡
mouseleave: 当鼠标移出元素时触发,该事件不支持冒泡
... ...
以及IE6 IE7 IE8中 的 change、select、submit、reset 事件事实上都没有参照规范定义产生事件冒泡。
当你在须要的冒泡的时候,绑定了这些事件,而你刚好不知道竟然还有事件天生就不支持冒泡的,那么你可能就悲剧了。因此这个点只要在脑壳里面有个印象就行了,我只记得我曾经遇到过这样一个坑,但暂时想不起来应用场景了 - -!
我所知道的,遇到过的关于事件流的坑就这么多了,想来应该也算是很是完整的一个总结了,值得你们点一下推荐和收藏的哦!