如何实现out-side-click功能

$ npm install jh-outside-click --save

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

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

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

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

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

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

如何实现out-side-click功能_第1张图片

方法其实很简单,不就是外部元素吗,我们直接在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__;
    },
  },
},

题外话

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

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

{
  rgba(0,0,0,0.8) solid 9999px
}
如何实现out-side-click功能_第2张图片

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

你可能感兴趣的:(如何实现out-side-click功能)