场景:因为有个需求就是鼠标经过可多选的 el-select 选择器时,需要有个气泡框显示已选的内容,其实 el-tooltip 气泡框可以满足需求,就是用 el-tooltip 气泡框来包裹 el-select 选择器,但是当选择器一个也没选中,即内容为空时不应该也显示气泡框,有点影响美观。应该就是若内容为空时,气泡框可以直接不显示出来。
因此,通过网上查找相关案例,自行设计一个仿Element UI的气泡框el-tooltip组件,不过多多少少不及官方Element UI的气泡框 el-tooltip 组件,只是可以满足内容为空时不显示气泡框,也就不需要v-if来判断内容是否为空,频繁创建与销毁组件,以及避免带来的用户体验问题。同时,支持输入的内容为整型、字符串、数组等,会有各自的显示。
父组件:index.vue
<template>
<div>
<div style="width: 300px; height: 300px; margin: 300px 200px; padding: 20px; background-color: #eee;">
<!-- 气泡框内容为空 -->
<MagicPopover :content="''">
<el-button size="mini">气泡框内容为空,直接不显示气泡框</el-button>
</MagicPopover>
<br /><br /><br />
<!-- 气泡框内容为整型 -->
<MagicPopover :content="content1">
<el-button size="mini">气泡框内容为整型</el-button>
</MagicPopover>
<br /><br /><br />
<!-- 气泡框内容为字符串 -->
<MagicPopover :content="content2">
<el-button size="mini">气泡框内容为字符串</el-button>
</MagicPopover>
<br /><br /><br />
<!-- 气泡框内容为数组 -->
<MagicPopover :content="content3">
<el-button size="mini">气泡框内容为数组</el-button>
</MagicPopover>
</div>
</div>
</template>
<script>
import MagicPopover from "./components/magicPopover";
export default {
components: {
MagicPopover
},
data: () => ({
content1: 5201314,
content2: 'HelloWorld',
content3: [5201314, 'HelloWorld']
})
}
</script>
<style scoped>
</style>
子组件:magicPopover.vue
<template>
<div
class="esse-popover"
@mouseenter="handleMouseEnterEvent"
@mouseleave="handleMouseLeaveEvent"
>
<transition name="fade">
<div
class="esse-popover-wrapper"
ref="essePopoverWrapperRef"
v-if="isView && content != null && content != ''"
>
<!-- 判断是否为数组 -->
<div v-if="(content instanceof Array)">
<p v-for="(item, key) of content" :key="key">{
{
item }}</p>
</div>
<!-- 其他类型,包括字符串、整型、对象... -->
<div v-else>
<p>{
{
content }}</p>
</div>
</div>
</transition>
<div ref="essePopoverSlotRef">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
props: [
'content'
],
data() {
return {
isView: false,
}
},
methods: {
/**
* 鼠标进入事件
*/
handleMouseEnterEvent(event) {
this.isView = true;
this.$nextTick(() => {
this.draw();
})
},
/**
* 鼠标离开事件
*/
handleMouseLeaveEvent(event) {
this.isView = false;
},
/**
* 渲染气泡框
*/
draw() {
if (this.content != null && this.content != '') {
document.body.appendChild(this.$refs.essePopoverWrapperRef);
let {
left, top, width} = this.$refs.essePopoverSlotRef.getBoundingClientRect();
// console.log('this.$refs.essePopoverSlotRef.getBoundingClientRect() =>', this.$refs.essePopoverSlotRef.getBoundingClientRect());
const offsetTop = 10;// 偏移高度
const offsetleft = width / 2;// 便宜位移,从左边计算
this.$refs.essePopoverWrapperRef.style.top = top - offsetTop + 'px';
this.$refs.essePopoverWrapperRef.style.left = left + offsetleft + 'px';
document.styleSheets[0].addRule('.esse-popover-wrapper::before','display: block; left: 50%; bottom: 0');// 显示三角形伪类元素
}
},
},
}
</script>
<style scoped>
.esse-popover {
width: auto;
display: inline-block;
position: relative;
}
.esse-popover-wrapper {
position: absolute;
z-index: 99;
width: 250px;
height: auto;
padding: 6px;
border: 1px solid #ebeef5;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.2);
background-color: #fff;
transform: translate(-50%, -100%);
}
.esse-popover-wrapper p {
margin: auto;
font-size: 13px;
}
/* 使用伪元素创建小三角形 */
.esse-popover-wrapper::before {
content: "";
position: absolute;
border-width: 6px 6px 0 6px;
border-style: solid;
border-color: transparent;
border-top-color: #fff;
transform: translate(-50%, 100%);
}
/* / 使用伪元素创建小三角形 */
/* 淡入淡出效果 */
.fade-enter-active {
/* transition: opacity 1s; */
transition: all ease 1s;
}
.fade-leave-active {
/* transition: opacity 0.3s; */
transition: all ease 0.3s;
}
.fade-enter, .fade-leave-to /* .fade-leave-active, 2.1.8 版本以下 */ {
opacity: 0;
}
/* / 淡入淡出效果 */
</style>
效果如下~
参考资料