您现在的位置是:网站首页> 编程资料编程资料
Vue基础popover弹出框编写及bug问题分析_vue.js_
2023-05-24
412人已围观
简介 Vue基础popover弹出框编写及bug问题分析_vue.js_
引言
最近做了一套Vue 的UI组件框架,里面牵涉到的popover组件个人觉得很有意思,也是个人觉得做出来最好看的一个组件。

首先新建一个Vue项目,无需赘述了。
制定结构
给组件命名为bl-popover
这是内容,这是内容,这是内容。 这是内容,这是内容,这是内容。
这种结构也许不错。
content的slot包裹popover里需要显示的内容,而原始默认slot里包裹popover触发器。
创建组件文件,实现基本功能
src目录创建popover.vue文件。
文件内部结构先写成这样,符合我对使用结构的印象,接着想要测试的话就注册这个组件,也无需赘述了。
设置为display:inline-block可不用占满一整行。
我们需要用触发器来显示和隐藏popover,所以在data里设置一个show属性。
让触发器被点击实现切换。但由于slot标签是不能接受任何东西的,所以我们把事件绑定在整个div上。
就变成了
此时即可实现点击button就可显示popover。
这时候我们需要做的就是将popover变为绝对定位。
绝对定位
给slot标签外包裹标签即可选中slot。
即可点击之后显示成这样

如何点击外部关闭
Bug:监听body问题。
name我该如何关闭这个popover呢?是点其他地方关闭吗?
本想这样处理:
methods:{ showChange(){ this.show = !this.show if(this.show===true){ document.body.addEventListener('click',()=>{ this.show = false }) } } } 但事实是,这样连popover都无法打开了。这是由于原生JS的事件冒泡机制。 this.show = !this.show和 this.show = false是在一次点击下全部完成了,所以他就直接给关了,根本看不见。
故这里我们将他改为异步,就不会一口气都走完了。
methods:{ showChange(){ this.show = !this.show if(this.show===true) { console.log('切换show'); setTimeout(()=>{ document.body.addEventListener('click', () => { this.show = false console.log('关闭show'); }) }) } } } } 即可解决这个开了就关的问题。
但是还有其他的问题。 实际上,body的大小只有蓝色边框内的部分

也就是点击蓝色边框之外的部分,是关不掉这个popover的。
所以不要监听body,直接监听document就好。
methods:{ showChange(){ this.show = !this.show if(this.show===true) { console.log('切换show'); setTimeout(()=>{ document.addEventListener('click', () => { this.show = false console.log('关闭show'); }) }) } } } } Bug:再次打开失败。
解决了点击外部失效的问题,我发现,点击打开popover,再点击外部关闭,就无法再次打开popover了。
这里来看控制台。
第一次点击触发器

第二次点击外部

第三次点击触发器

会发现第三次点击直接走完了切换和关闭。
这是为什么呢,因为这时候有两个事件监听器在运作,一个是popover上的,一个是document上的。顺序是先调用popover上的,再调用document上的。
我们再来看看第四次点击触发器

再看看第五次,第六次

会发现关闭show出现越来越多次,这是为什么呢。这是因为我们点击一次触发器,执行一次showChange方法,就会在document上新增一个addEventListener,而我们并没有在时间结束之后删除他,就越来越多,越来越多。
那么我们就需要在每次popover关闭之后,删除他。
methods:{ showChange(){ this.show = !this.show if(this.show===true) { console.log('切换show'); setTimeout(()=>{ document.addEventListener('click', function listener{ this.show = false console.log('关闭show'); document.removeEventListener('click',listener) console.log('删除监听器'); }.bind(this)) }) } } } } 这里我们需要removeEventListener,所以监听器需要有个函数名,我起名为listener,但不是箭头函数了,this.show的this就不是指向Vue实例了,而是调用这个监听器的document了。所以需要使用bind把this绑定一下。
此时前两次点击是

但是第三次点击

说明还是有bug,看起来这个删除监听器根本就没有成功。
这里的原因比较复杂。我为了让listener内的this还是指向Vue实例,使用了bind,但其实使用了bind之后的listener并不是原本的listener了,而是绑定后返回的一个新的函数。所以并没有删掉原本的listener。所以在这里要避免使用bind。
methods:{ showChange(){ this.show = !this.show if(this.show===true) { console.log('切换show'); setTimeout(()=>{ let listener = () =>{ console.log('新增事件监听器'); this.show = false console.log('关闭show'); document.removeEventListener('click',listener) console.log('删除监听器'); } document.addEventListener('click',listener) }) } } } 新建了一个箭头函数,就避免了使用bind。
这是此时点击了六次的结果,可以正常开闭popover了。

Bug:点击popover气泡本身也会关闭popover
虽然开闭正常了,但是点击气泡本身,我本身不希望他隐藏,可他还是关闭了。
这是因为事件冒泡的原因,我们点击popover或者触发器,事件会冒泡到document上面去,还是会触发。
我这时选择了这个处理方法
在可以被点击的地方使用了.stop阻止冒泡,可以发现,点击气泡不会被关闭了,并且document上的事件监听器也没有产生或触发。

这样就实现了一个最简单的popover。
其他Bug
Bug:外部有overflow:hidden,会遮挡popover。
我在popover组件的外部套一个div,设置overflow:hidden,会发生这样的情况

会被挡住。
说明这个问题非常严重,代码可能要全部砍倒重练。
而且单纯地阻止冒泡也会带来很多问题,会打断用户的事件链。
那我选择让这个弹出框气泡移到body上,就可以避免这个问题。

可以看到,为了能让v-if===false的情况下,也能检查的到contentWrapper,我把v-if换成了v-show,因为v-show只是切换display:none,影响的是元素的显示隐藏。而v-if影响的是元素是否被render到DOM树上。
但是使用v-show就会让contentWrapper一开始就存在在页面上,我并不想这样。
提示:
本文由神整理自网络,如有侵权请联系本站删除!
本站声明:
1、本站所有资源均来源于互联网,不保证100%完整、不提供任何技术支持;
2、本站所发布的文章以及附件仅限用于学习和研究目的;不得将用于商业或者非法用途;否则由此产生的法律后果,本站概不负责!
相关内容
- element-ui配合node实现自定义上传文件方式_vue.js_
- redux功能强大的Middleware中间件使用学习_React_
- 如何在ElementUI的上传组件el-upload中设置header_vue.js_
- 微信小程序实现活动报名登记功能(实例代码)_javascript技巧_
- 解析Clipboard API剪贴板操作实例_JavaScript_
- React Hooks useReducer 逃避deps组件渲染次数增加陷阱_React_
- 使用vue-router切换组件时使组件不销毁问题_vue.js_
- JavaScript 字符串新增方法 trim() 的使用说明_javascript技巧_
- vue中百度地图定位及附近搜索功能使用步骤_vue.js_
- JS前端同源策略和跨域及防抖节流详解_JavaScript_
点击排行
本栏推荐
