// 第一種作法,用插槽作 <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