1. popover是什麼以及難點在哪
- 點一下出現一個卡片,也叫氣泡卡片
- 難點在於css的樣式
2. 用戶會怎麼去用
// 第一種作法,用插槽作
<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>複製代碼
3. 爲何要用用inline-block,由於這樣多個popover組件纔不會一行
// 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>複製代碼
4. 優秀的前端css必定是寫的很6的
// 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>複製代碼
5. 開始完善功能,實現點外面以後內容消失
// 這樣寫會出現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用異步解決
複製代碼
6.解決第三次點擊不行
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,實現最簡單的popover
// 經過如下代碼發現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>
複製代碼
8. 目前還有哪些沒有實現
- 用戶有的時候但願是hover的時候顯示,支持多種事件
- 假設在外面寫一個div,有overflow:hidden的屬性就會出bug,這就是其它的框架都把popover放外面的緣由
最後,歡迎交流