美文网首页
使用vue开发popover组件接连踩坑过程实录

使用vue开发popover组件接连踩坑过程实录

作者: 卡布i | 来源:发表于2020-01-21 00:01 被阅读0次

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的值来控制文本的显示与隐藏

image.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                
  })            
}

浏览器控制台

image.png

两个log依次执行,所以popover刚开启就被关闭了

改用异步代码

if (this.visible === true) {        
  setTimeout(() => {          
    document.addEventListener("click", () => {            
    console.log("点击document隐藏popover");            
    this.visible = false;          
    });        
  }, 500);      
}

多点击几次,会发现popover组件出问题了,点击一次会执行很多次log

分析代码会发现,我们没有清除click事件队列,导致事件越来越多

image.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);        
  });      
}

浏览器控制台

image.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就无法正确出现了

相关文章

网友评论

      本文标题:使用vue开发popover组件接连踩坑过程实录

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