美文网首页让前端飞Web前端之路
如何实现out-side-click功能[点击外部元素触发某事件

如何实现out-side-click功能[点击外部元素触发某事件

作者: MASON_S | 来源:发表于2019-08-10 13:10 被阅读0次
    $ npm install jh-outside-click --save
    

    在日常开发中,我们常常会遇到这样的需求

    点击特定元素外的时候触发某个事件

    具体表现为做一个弹窗时,点击弹窗外的任意部分,如遮罩层,则自动关闭弹窗。

    特定元素弹窗内容层
    外部元素除了内容层外的其他一切元素

    常规做法是设置遮罩层与内容层不是父子元素,然后专门在遮罩层上注册点击事件,当遮罩层被点击时,触发关闭弹窗方法。
    这其实是一种曲线救国的方法,只是实现了触发特定事件的效果,并没有监听到外部元素的点击。

    如果这时候我说,没有遮罩层,那又该怎么实现呢?

    方法其实很简单,不就是外部元素吗,我们直接在body上注册临时事件,判断点击元素是否为特定元素外的,如果是,那就触发关闭方法。

    怎么注册临时事件呢?
    在body上注册事件是全局的,每一个元素都会被监听到,要怎么才能做到临时呢?

    我们只需要在关闭方法内再去remove掉body的监听,这样就做到临时监听了。

    怎么判断是否为外部元素?
    方法有两种,第一种是最简单的,使用contains

    node.contains( otherNode )

    • node 是否包含otherNode节点.
    • otherNode 是否是node的后代节点.
      如果 otherNode 是 node 的后代节点或是 node 节点本身.则返回true , 否则返回 false。

    第二种使用getBoundingClientRect

    Element.getBoundingClientRect()方法返回元素的大小及其相对于视口的位置

    通过对比当前点击元素的坐标与特定元素的位置信息,也可以得出是否为外部点击。


    在原生js上实现

    document.body.append(this.el); // 插入弹窗内容
    // 在弹窗dom上添加自定义属性(方法)
    this.el.__outsideClickEvent__ = e => {
            // 判断是否外部点击
        if (!this.el.contains(e.target)) {
            this.hide(); // 触发关闭方法
        }
    };
    setTimeout(() => {
            // 注册事件
        document.body.addEventListener('click', this.el.__outsideClickEvent__);
    });
    
    hide(){
        // todo
        // 移除事件
        document.body.removeEventListener('click', this.el.__outsideClickEvent__);
        // 删除属性
        delete this.el.__outsideClickEvent__;
    }
    

    在vue上实现
    在vue上我们更多是用自定义指令来实现,做法如下

    directives: {
      'out-side-click': {
        bind(el, binding) {
          el.__outsideClickEvent__ = e => {
            // 也可使用getBoundingClientRect检查
            if (!el.contains(e.target)) {
              binding.value(e);
            }
          };
          setTimeout(() => {
            document.body.addEventListener('click', el.__outsideClickEvent__);
          });
        },
        unbind(el) {
          document.body.removeEventListener('click', el.__outsideClickEvent__);
          delete el.__outsideClickEvent__;
        },
      },
    },
    
    <div class="content" v-out-side-click="close"></div>
    

    题外话

    如果没有了遮罩层元素,又要怎么实现非弹窗区半透明效果呢?

    outline可以帮我们解决问题,设置一个足够大的尺寸就可以了

    {
      rgba(0,0,0,0.8) solid 9999px
    }
    

    当然如果有做操作引导的需求,outline也是一个好选择。

    相关文章

      网友评论

        本文标题:如何实现out-side-click功能[点击外部元素触发某事件

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