背景
最近项目中需要实现一个需求,“点击结果列表中的每一项都出现其对应的详情弹框。”
这种需求最适合使用popover来实现了。
trigger属性用于设置何时触发 Popover,支持四种触发方式:hover,click,focus和manual。对于触发 Popover 的元素,有两种写法:
- 使用
slot="reference"的具名插槽.- 使用自定义指令
v-popover指向 Popover 的索引ref。
两种元素实现方式可查看官方文档:弹出框 Popover。在本文中,只使用第一种slot方式。
需求设计和实现
触发方式的选用
现在分析上面我的需求,出现了“点击”二字,貌似看起来使用click点击触发和manual手动触发都可以实现。
但是,经过我的实践,手动触发被我pass掉了。
原因是,manual的实现方式是靠v-model判断显隐条件。
<el-popover
placement="right"
width="400"
trigger="manual"
v-model="visible"
>
<el-form ref="form"
...
>
...
</el-form>
<el-button slot="reference">click出现</el-button>
</el-popover>
通过v-model的方式设置一个visible,控制visible的值,是可以解决单个表单的Popover弹出框显隐问题的。
但是我的需求是要在Tree树结构上做每条数据的popover。只靠一个visible值会导致所有popover弹窗同时出现和同时隐藏。
这一点儿也不满足要求!!!
所以,要用click了。同时还有一个好处,使用click的触发方式还能自带一些功能。比如
- 二次点击该数据可隐藏弹框。
- 点击页面空白处也可隐藏弹框。
Tree树结构中的显隐条件实现
解决办法是:通过每条数据的唯一id给每个popover增加一个ref,用来判断自己的显隐。
<el-tree
:data="attrsList"
node-key="index"
>
<div
class="attr-list"
slot-scope="{ node, data }"
>
<div
class="attr-list-item"
@click="handleClick(data, node)"
>
<el-popover
:ref="'handle' + node.data.id"
placement="left"
width="250"
trigger="click"
>
<el-form ref="form" :model="form" >
<el-form-item>
...
</el-form-item>
</el-form>
<el-button @click="handleffirm" >确定</el-button>
<div class="attr-list-item-content" slot="reference">
{{node.label}}
</div>
</el-popover>
</div>
</div>
</el-tree>
我给每条数据增加了一个点击事件handleClick,和一个data字段selectedPoppverId用于控制前一个popover的隐藏和最新一个popover的展示。
<script>
export default {
name: 'treeTest',
data () {
return {
form: {...},
selectedPoppverId:''
}
},
methods: {
handleClick () {
//隐藏上一个显示的popover
let refName = 'handle' + this.selectedPoppverId;
//第一次点击时,this.$refs[refName]为空,所以需要做个是否为空的判断
this.$refs[refName] && this.$refs[refName].doClose();
//关闭上一个popover后,给selectedPoppverId赋值新点击的那条数据的id
this.selectedPoppverId = node.data.id;
//显示新点击的数据的popover
refName = 'handle' + this.selectedPoppverId;
this.$refs[refName].doShow();
},
}
}
</script>
一些问题和优化点
有时候doClose不生效?
在实现时,ref使用变量的形式,因为是多个循环的popover。如果需要点击确定来关闭el-popover窗口,却发现只引用doClose方法不生效,关不掉。
那么可以通过模拟点击页面空白处来实现。简单高效。。。
//点击确定时,关闭popover,最简单直接的方式就是模拟点击页面空白处
handleffirm () {
document.body.click();
},
Tree结构中,我想让他点击父节点不出现popover,点击子节点的时候才出现。
在handleClick里加个判断就好了。
if(node.childNodes.length === 0) {
...//当前节点没有子节点的时候才执行doShow()
}
popover中内容过高,丢到可视范围外了
在使用2.x版本的element-UI时,里面的Popover 气泡卡片组件,有自带的自动适应位置的功能;在 element plus 中,直接使用,已经无法自适应气泡弹窗的位置了。
想要在页面里,当 Popover 弹出框的位置接近边界时,应该自动切换到相反的方向进行显示。
<fin-popover
placement="left"
width="250"
trigger="click"
:fallback-placements="['bottom', 'top', 'right', 'left']"
>
</fin-popover>
<!----**注意:** 适用于 `ele-plus`版本, `2.x` 版本的 `element` 自带有这个功能;--->
我popover中展示的都是动态获取的数据,怎么数据不对呀
上面实现了多条数据popover的显隐效果。当然,一般的项目需求中,popover内的数据也都是动态获取的。那么就需要手动做实时更新。在执行doShow方法前先执行updatePopper方法。
if( this.$refs[refName]) {
this.$refs[refName].updatePopper()
this.$nextTick(() => {
this.$refs[refName].doShow();
})
}
以上,大致就能实现普通的项目需求了。其实也能看出来,popover和tooltip的功能很相似。
官方文档上都说了,“Popover 的属性与 Tooltip 很类似,它们都是基于
Vue-popper开发的,因此对于重复属性,请参考 Tooltip 的文档,在此文档中不做详尽解释。”