在做pokemonUI项目的popover组件时,需要实现点击出现内容然后点击空白地方可以实现隐藏内容的功能。
初次失败
为了实现这个功能我们有一个初步的想法:
当visible为true时,即内容显示时,我们添加一个事件监听,当我们点击body的部分时,让visible为false来实现隐藏。这时我们发现,刚开启就被关闭了。
解决方案
所以我们使用异步,这里我们先选择nextTick来进行异步操作。 Vue3中 nextTick的使用略有不同 根据Vue3的官方文档可以得知使用方法
<script>
import { nextTick } from 'vue'
export default {
data() {
return {
count: 0
}
},
methods: {
async increment() {
this.count++
// DOM not yet updated
console.log(document.getElementById('counter').textContent) // 0
await nextTick()
// DOM is now updated
console.log(document.getElementById('counter').textContent) // 1
}
}
}
</script>
<template>
<button id="counter" @click="increment">{{ count }}</button>
</template>
但是我们在通过log调试法的时候发现1和2同时打出,也就是点击之后立即触发了回调,visible马上被设置成了false。于是我们转换一下思路
继续解决
这次我们使用setTimeout
值得一提的是,这样写忽略了一个问题,我们点击关闭popover是,还需要将click的事件监听移除,否则只能点两次,一直增加事件监听。
再删除的时候,由于我们的事件监听函数是个箭头函数无法指向,我们需要改成具名函数,所以需要在后面bind(this)这样子我们在移除这个函数的时候实际上是移除了x.bind()这个函数。所以需要单独定义一下。
优化结果:
export default {
name: 'pokemonPopover',
data() {
return {visible: false}
},
methods: {
show() {
this.visible = !this.visible
if (this.visible === true) {
setTimeout(() => {
let eventHandler = () => {
this.visible = false
document.removeEventListener('click', eventHandler)
}
document.addEventListener('click', eventHandler)
}, 0)
}
}
}
}