ps:只是说明思路,生产中不采用此方式
html代码:
<div id='app'>
<g-popover>
<template slot="content">
<div>popover里面的内容</div>
</template>
<button>点击</button>
</g-popover></div>复制代码
vue组件代码:
<template>
<div class="popover" @click="onClick">
<div class="content-wrapper" v-if="visible">
<slot name="content"></slot>
</div>
<slot></slot>
</div>
</template>
<script>
export default {
name: "GuLuPopover",
data(){
return {visible:false}
},
methods:{
onClick(){
this.visible = !this.visible
}
}
}</script>复制代码
通过给按钮添加click方法,切换visible的值来控制文本的显示与隐藏
![](https://img.haomeiwen.com/i9022064/808f2da604e093ff.png)
接下来实现点击空白部分关闭popover,
最容易想到的思路是在切换visible时监听document的click事件
// 建议监听document而不是document.body,否则关闭区域会受body高度影响
onClick(){
this.visible = !this.visible if(this.visible === true){ document.addEventListener('click',()=>{ this.visible = false }) }
这时会发现popover没有出现,我们来看log
onClick(){
this.visible = !this.visible
console.log('改变visible的值')
if(this.visible === true){
document.addEventListener('click',()=>{
console.log('点击document隐藏popover')
this.visible = false
})
}
浏览器控制台
![](https://img.haomeiwen.com/i9022064/c4ebb32872bc0e14.png)
两个log依次执行,所以popover刚开启就被关闭了
改用异步代码
if (this.visible === true) {
setTimeout(() => {
document.addEventListener("click", () => {
console.log("点击document隐藏popover");
this.visible = false;
});
}, 500);
}
多点击几次,会发现popover组件出问题了,点击一次会执行很多次log
分析代码会发现,我们没有清除click事件队列,导致事件越来越多
![](https://img.haomeiwen.com/i9022064/ce292211de569778.png)
在popover隐藏后要清除click事件,为了方便,改写剪头函数,并绑定this
if (this.visible === true) {
setTimeout(() => {
document.addEventListener("click",
function x(){
console.log("点击document隐藏popover");
this.visible = false;
document.removeEventListener('click',x)
}.bind(this));
}, 500);
}
结果发现,事件监听队列还是继续叠加,好像并没有成功的删除监听器
这是因为x.bind会生成一个新的函数,所以我们添加的函数和我们的删除的函数并不是同一个
解决方法是给箭头函数取一个名字
if (this.visible === true) {
setTimeout(() => {
let eventHandler = ()=>{
this.visible = false; console.log('点击document关闭popover') document.removeEventListener('click',eventHandler)
}
document.addEventListener("click",
eventHandler);
});
}
浏览器控制台
![](https://img.haomeiwen.com/i9022064/874a73340f45e976.png)
好了,暂时解决了一个bug
另一个细节是popover出现后,点击button按钮会隐藏两次popover
第一次是button按钮点击后,切换visible的值,组件自身隐藏popover
同时button按钮也在document区域内,点击按钮同样会触发事件队列,再隐藏一次popover
另一个bug是点击popover区域也会隐藏popover
这明显是不合理的,如果用户要复制popover里面的内容怎么办?
上面两个问题都可以通过阻止冒泡解决
<div class="popover" @click.stop="onClick">
<div class="content-wrapper" v-if="visible" @click.stop>
<slot name="content"></slot>
</div>
<slot></slot>
</div>
click.stop解决bug的同时也会带来新的问题,就是用户无法给button添加click事件,所以这不是最终解决办法,同时popover不应该和button放在同一层级,否则用户写一个overflow:hidden,
popover就无法正确出现了
网友评论