资讯专栏INFORMATION COLUMN

又被事件冒泡坑了一把,这次要彻底弄懂浏览器的事件流

TIGERB / 3448人阅读

摘要:事件冒泡一个简单,但是坑了我无数回的知识点与的交互通过事件来实现。而浏览器的事件流是一个非常重要的概念。不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议,只需要知道在中规定的事件流包括了三个部分,事件捕获阶段处于目标阶段事件冒泡阶段。

打算封装一个弹窗组件,做的时候忘记了考虑事件冒泡的因素,结果被坑得不要不要的。为了解决自己的问题,去查阅了不少资料,把事件流相关的知识都给总结一下。

事件冒泡:一个简单,但是坑了我无数回的知识点!

JavaScript与HTML的交互通过事件来实现。而浏览器的事件流是一个非常重要的概念。不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议,只需要知道在DOM2中规定的事件流包括了三个部分,事件捕获阶段、处于目标阶段、事件冒泡阶段。

一、事件捕获

事件捕获,是从document元素开始,越高级的父级元素越早接收到事件,因此这是一个从上而下的过程。

还是那句话,没在实际应用中踩过坑,可能你真的不算掌握了这个知识点。那么,事件捕获有什么常见的坑呢?

1. 坑一:新插入的子元素没有绑定点击事件

可能不少同学在初学js的时候遇到过这样一个坑。一个ul元素中初始的状态有4个li元素,我们可以循环给li元素添加click事件,执行我们想要的动作。这个例子的坑就在于,新添加的li元素不会有我们绑定的click事件。

是的,就是这么坑,为了解决这个问题,我们就要利用事件捕获的原理。

$("ul.container").click(function(event) {
    var target = event.target;
    if (target.className == "item") {
        // dosomething
    }
})

在上面的解决方案中,我并不是直接给li绑定事件,而是给所有li的父级ul绑定事件。根据事件捕获的原理,事件会自上而下传递给li,我们只需要通过一些简单的条件判断来确定我们的目标元素即可,如上例中的判断li的className。

这个方式就是大名鼎鼎的事件委托。

事件委托是一个很重要而且在实际中会常常用到的知识点。

2. 坑二: 如果目标元素有子元素,那么怎么办?

当我们在使用className判断目标元素时,会遇到这样的情况。

...
  • xxx

    xxxxxxs

  • ...

    当我们试图使用事件委托希望给所有的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事件都会执行,自下而上按顺序执行

    click

    我为这个事情写了一个小例子,大家可以动手感受一下这个坑。点击空白会生成一个弹窗

    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 事件事实上都没有参照规范定义产生事件冒泡。

    当你在需要的冒泡的时候,绑定了这些事件,而你恰好不知道居然还有事件天生就不支持冒泡的,那么你可能就悲剧了。所以这个点只要在脑袋里面有个印象就好了,我只记得我曾经遇到过这样一个坑,但暂时想不起来应用场景了 - -!

    我所知道的,遇到过的关于事件流的坑就这么多了,想来应该也算是非常完整的一个总结了,值得大家点一下推荐和收藏的哦!

    文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

    转载请注明本文地址:https://www.ucloud.cn/yun/49871.html

    相关文章

    • 又被事件冒泡坑了一把这次彻底弄懂览器事件

      摘要:事件冒泡一个简单,但是坑了我无数回的知识点与的交互通过事件来实现。而浏览器的事件流是一个非常重要的概念。不去讨论那些古老的浏览器有事件捕获与事件冒泡的争议,只需要知道在中规定的事件流包括了三个部分,事件捕获阶段处于目标阶段事件冒泡阶段。 打算封装一个弹窗组件,做的时候忘记了考虑事件冒泡的因素,结果被坑得不要不要的。为了解决自己的问题,去查阅了不少资料,把事件流相关的知识都给总结一下。 ...

      Ocean 评论0 收藏0
    • JS 中事件冒泡与捕获

      摘要:在之前是只支持事件冒泡,包括之后和目前主流的浏览器都同时支持两种事件。中可以用来取消事件冒泡。 刚接触 JS 的那个时候,啥也不懂,只想着如何利用 Google、百度到的函数来解决实际的问题,不会想到去一探究竟。 渐渐的,对 JS 的语言的不断深入,有机会去了解一些原理性东西。最近在看 JQuery 源码,感触很多,总想着用原生的 JS 去实现自己的一个 JQuery 库。说实在的,J...

      Rindia 评论0 收藏0
    • 彻底弄懂函数防抖和函数节

      摘要:若时间差大于间隔时间,则立刻执行一次函数。不同点函数防抖,在一段连续操作结束后,处理回调,利用和实现。函数防抖关注一定时间连续触发的事件只在最后执行一次,而函数节流侧重于一段时间内只执行一次。 原博客地址,欢迎star 函数防抖和节流 函数防抖和函数节流:优化高频率执行js代码的一种手段,js中的一些事件如浏览器的resize、scroll,鼠标的mousemove、mouseover...

      Mr_houzi 评论0 收藏0

    发表评论

    0条评论

    TIGERB

    |高级讲师

    TA的文章

    阅读更多
    最新活动
    阅读需要支付1元查看
    <