美文网首页饥人谷技术博客Web前端之路
从“点击别处关闭浮层”了解事件传播机制

从“点击别处关闭浮层”了解事件传播机制

作者: 许骁Charles | 来源:发表于2019-05-01 15:03 被阅读68次

    写出一个点开浮层、关闭浮层的例子,要求:
    1)点击按钮弹出浮层
    2)点击别处关闭浮层
    3)点击浮层时,浮层不得关闭
    4)再次点击按钮,浮层消失

    第一次尝试:

    (1)监听 body

    新手最容易想到的方式是,监听 body,如下图:

    然而,此时点击按钮并不会弹出浮层,却能正常输出 'block''none'。并且由于 button 父元素 wrapper 的高度并不是全屏幕,因此点击屏幕其他空白处,因为 body 监听不到点击事件,连 none 都无法打印。

    (2)监听 document

    那么换成监听 document,即整个页面后,会成功吗?

    同样也是无法弹出浮层的。

    这是因为,事件在冒泡过程中,冒泡顺序是由子到父的顺序,即先监听到了 buttonclick 事件,接着马上监听到了 documentclick 事件,浮层确实有弹出过,但是立马又被 display: none; 隐藏了。

    (3)stopPropagation()

    那么如何解决被连续监听呢,首先想到的答案是阻止事件冒泡,即 stopPropagation() 方法,详见代码。如下图:

    (4)监听按钮父元素

    似乎功能实现了,但是此时点击浮层自身,浮层也会消失。因此如果浮层内部还有内容需要操作时,则应当在 wapper 上阻止冒泡,而不是 button

    这是终极答案了么?

    第二次尝试

    上面的方法中,每次点击屏幕都会触发 document 的点击事件,当按钮非常多,且有许多无意识点击屏幕空白处的时候,这种方法就非常消耗内存了。

    (1)一次监听 one()

    在按钮的监听事件中,阻止冒泡,并且使用 one() 方法做到只有当按钮被点击之后 document 才添加对点击事件的的一次监听,document 对于其他点击事件不监听,以节省内存。

    注意:如果在 checkbox 父元素的任何一层(包括 checkbox 自己)添加了 preventDefault() 方法,那么 checkbox 将无法被 check。如下:

    (2)延迟函数

    思考上面(1)一次监听中的代码,如果不阻止冒泡,应该怎么做呢?

    答案是用延迟函数 setTimeout,这样做会在冒泡阶段结束后再添加 one click 监听函数。

    下图为整个浮层 show()hide() 的整个过程,也可以验证函数的执行顺序。

    第三次尝试

    上面的代码,有两个bug:

    1. 虽然延迟函数能代替阻止冒泡实现 show() 之后不立即 hide() ,但是点击浮层自身仍然会隐藏
    2. 如果只点击按钮,那么点击两次之后,因为没有对按钮做判断,将无法再显示出浮层

    最终改良代码

    $(clickMe).on('click', function() {
        if (popover.style.display == 'block') {
            $(popover).hide()
        } else {
            $(popover).show()
    
            $(document).one('click', function() {
                $(popover).hide()
            })
        }
    })
    
    $(wrapper).on('click', function(e) {
        e.stopPropagation()
    })
    

    新思路(待填坑)

    遮罩层

    在弹窗和所有页面其他内容之间放一个透明层,点那个层的时候关闭。

    stack overflow 思路

    $(document).mouseup(function(e){
      var _con = $(' 目标区域 ');   // 设置目标区域
      if(!_con.is(e.target) && _con.has(e.target).length === 0){ // Mark 1
        some code...   // 功能代码
      }
    });
    /* Mark 1 的原理:
    判断点击事件发生在区域外的条件是:
    1. 点击事件的对象不是目标区域本身
    2. 事件对象同时也不是目标区域的子元素
    */
    

    相关文章

      网友评论

        本文标题:从“点击别处关闭浮层”了解事件传播机制

        本文链接:https://www.haomeiwen.com/subject/emeiiqtx.html