// 第一种作法,用插槽作 <g-popover> <template slot="content"> <div></div> </template> <template slot="trigger"> <button>点我</button> </template> </g-popover> // 第二种作法,用指令作,这种方式不太用,指令大多数是造轮子用的因此就用第一种方法作 <div ref="xxx"></div> <button v-popover="$refs.xxx"></button>
// popover.vue <template> <div class="popover"> <slot name="content"></slot> <slot></slot> </div> </template> .popover{ display: inline-block; vertical-align: top; } // index.html <div id="app"> <g-popover> <template slot="content"> <div>popover内容1</div> </template> <button>点我1</button> </g-popover> <g-popover> <template slot="content"> <div>popover内容2</div> </template> <button>点我2</button> </g-popover> </div>
// popover.vue <template> <div class="popover" @click="xxx"> <div class="content-wrapper" v-if="visible" > <slot name="content"></slot> </div> <slot></slot> </div> </template> <script lang="ts"> export default { name: "GuluPopover", data (){ return {visible:false} }, methods: { xxx(){ this.visible = !this.visible } } } </script> <style lang="scss" scoped> .popover{ display: inline-block; vertical-align: top; position: relative; .content-wrapper{ position: absolute; bottom: 100%; left: 0; border: 1px solid red; box-shadow: 0 0 3px rgba(0,0,0,0.5); } } </style>
// 这样写会出现bug,刚出现外面就会点击,也就是刚开启就会关闭 // 出现缘由是点击的时候就建了eventListener,而不是出现了再建eventListener // 具体涉及到原生js的一些核心,叫作事件机制,事件的冒泡机制 methods: { xxx(){ this.visible = !this.visible console.log('切换 visible') if(this.visible === true) { document.body.addEventListener('click', ()=>{ this.visible = false console.log('点击body就关闭popover') }) } } } // 这个bug用异步解决
if(this.visible === true) { // 这样写仍是不行 // this.$nextTick(() => { // document.addEventListener('click', ()=>{ // this.visible = false // console.log("进入click") // console.log(this.visible); // }) // }) setTimeout(()=>{ document.addEventListener('click', ()=>{ this.visible = false console.log("进入click") console.log(this.visible); }) }) }
methods: { xxx(){ this.visible = !this.visible if(this.visible === true) { setTimeout(()=>{ console.log("新增 document click 监听器") document.addEventListener('click', function x(){ this.visible = false; console.log('删除监听器') document.removeEventListener('click',x) // 可是这句话有问题,我删除的x,并非我绑定的,我绑定的是x,bind this以后的新函数, console.log('点击body就关闭popover') }.bind(this) ) }) } } } // 这样写也有个坑,缘由是 x() x.bind()会变成一个新的函数,
methods: { xxx(){ this.visible = !this.visible console.log(this.visible) console.log('切换 visible') if(this.visible === true) { setTimeout(()=>{ let eventHander = ()=>{ this.visible = false; document.removeEventListener('click',eventHander) } document.addEventListener('click', eventHander) }) } } }
解决点击popover关闭的bug,实现最简单的popovercss
// 经过如下代码发现vm 隐藏了一次popover,document隐藏了一次 methods: { xxx(){ this.visible = !this.visible if(this.visible === true) { setTimeout(()=>{ let eventHandler = ()=>{ this.visible = false; console.log('document 隐藏 popover') document.removeEventListener('click',eventHandler) } document.addEventListener('click', eventHandler) }) }else{ console.log('vm 隐藏 popover') } } } // 因此须要阻止冒泡,让popover事件在其内部进行处理就能够了 <div class="popover" @click.stop="xxx"> <div class="content-wrapper" v-if="visible" @click.stop> <slot name="content"></slot> </div> <slot></slot> </div>
<img src="https://i.loli.net/2020/01/27/gS4ZwP6zfAvULYT.jpg" alt="微信" width="400" height="400" align="bottom" />html