JS事件在Vue中的小坑

360 阅读2分钟

一、在开发popover遇到的问题

我需要点击按钮弹出气泡,点击页面其他地方气泡消失,我们首先就想到了下面代码

点击按钮时给pop一个条件语句,如果visible是true那么就给document一个事件监听,点击网页就会把visible变成false

<template>
  <div class="popover" @click="pop" v-if="visible">
  </div>
</template>

<script>
export default {
  data() {
    return { visible: false };
  },
  methods: {
    pop() {
      this.visible = !this.visible;
      if (this.visible === true) {
        document.addEventListener("click", ()=>{
            this.visible = !this.visible
            });
          }
      }
    }
  }
};
</script>

二、第一个问题-点击按钮都无法做到出现气泡

此时连点击按钮都无法做到出现气泡

因为监听函数,只会在冒泡阶段触发。当div触发pop时添加监听函数,click继续冒泡,document触发了它的回调函数。结果就是visible没变

    pop() {
      this.visible = !this.visible;
      if (this.visible === true) {
        setTimeout(() => {
          function outClick(){
            this.visible = false;
          }
          document.addEventListener("click", outClick);
        },0);
      }
    }

加入异步处理即可,把事件监听推迟到click冒泡结束

三、第三个问题-点击页面任何地方无法取消气泡

此时依然做不到点击页面任何地方取消气泡。

addEventListener监听函数内部的this指向事件所在的对象,即document

document.addEventListener("click", outClick.bind(this));

problem solved!

四、第四个问题-第三次点击没有任何反应

初步判断是由于document的监听函数没有被移除,所以第三次点击按钮(第一次二次分别弹出和移除)同时触发两个监听函数。

我们加一个 removeEventListener 理论上就可以了

  methods: {
    pop() {
      this.visible = !this.visible;
      if (this.visible === true) {
        setTimeout(() => {
          function outClick(){
            this.visible = false;
            document.removeEventListener("click", outClick.bind(this));
          }
          document.addEventListener("click", outClick.bind(this));
        },0);
      }
    }
  }

结果发现不行,是因为bind() 方法创建的是一个新的函数, removeEventListener 的不是同一个回调

  methods: {
    pop() {
      this.visible = !this.visible;
      if (this.visible === true) {
        setTimeout(() => {
          const outClick = () => {
            this.visible = false;
            document.removeEventListener("click", outClick);
          };
          document.addEventListener("click", outClick);
        }, 0);
      }
    }
  }

箭头函数固定this

problem solved!