前言
作为一个前端靓仔,平时日常开发时经常会涉及到 popover(组件 | Element) 这个组件。
一般都是在B端列表处使用会比较多,比如在商品名称或有提示性icon的地方,使用popover来展示完整信息。
但是我们都知道,普通的popover是不会判断当前内容是否超出隐藏了!如下:
图一:
图二:
图一内容已经超出了,所以我们应该使用popover去展示完整内容。
图二当前宽度已经示完整内容,所以没必要使用popover。
目前的使用情况下,无论是否超出都会直接显示,这显然是体验不好的。
因此基于popover的基础上,我设计了overflow-popover。
下面附上可直接使用的源码和组件文档。
需要的朋友直接去拿
代码实现
效果如下:
通过上面的效果图可以看到:
鼠标移上超出隐藏的内容时———popover组件展示。
鼠标移到未隐藏内容时——popover组件不显示。
核心原理
一、设置插槽
popover的内容可以通过插槽去设置
<el-popover >
<template slot="reference">
</template>
</el-popover>
修改一下改成:
<el-popover >
<template slot="reference">
// 在el-popover的插槽中插入一个div,并提供一个默认插槽
<div ref="reference">
<slot/>
</div>
</template>
</el-popover>
将el-popover原来的slot中默认写入一个div,通过div下slot实现插入数据的功能。
这样的好处的div的宽高会被内容所撑开,而我们通过getBoundingClientRect()方法可以获得这个div的实际宽高,通过比较实际宽高和设置的最大宽度,就可以知道是否应该禁用popover。
二、设置移入移出事件
在div处设置鼠标移入移出的事件
<el-popover >
<template slot="reference">
// 在el-popover的插槽中插入一个div,并提供一个默认插槽
<div
@mouseenter="checkIsShowPopover"
@mouseleave="checkIsShowPopover"
ref="reference">
<slot/>
</div>
</template>
</el-popover>
在触发鼠标移入移出时,我们可以做对这个div宽的判断
三、通过移入移出事件判断是否禁用popover
针对宽度判断是否禁用popover
// checkIsShowPopover方法
checkIsShowPopover() {
// 最大宽度
const maxWidth = 180
// 实际宽度
const { width } = this.$refs.reference.getBoundingClientRect();
if( width < maxWidth ) {
// 说明内容还没出现...
// 禁用popover
} else {
// 放开popover
}
}
通过这个方法就能实现当前的div宽度是否达到极限,是否应该禁用popover
四、针对多行,超出隐藏...的处理
上面介绍了针对一行最大宽度的处理,但有时候会有多行超出隐藏的需求。(比如超出2行的部分隐藏)
同上:(针对高度判断是否禁用popover)
值得注意的是 this.$refs.reference.scrollHeight; 可以获得这个div应该渲染的实际高度
可以通过比较getBoundingClientRect()的height属性和this.$refs.reference.scrollHeight判断是否已经超出最大高度
// checkIsShowPopover方法
checkIsShowPopover() {
// 真实高度
const realHeight = this.$refs.reference.scrollHeight
// 实际宽度
const { height } = this.$refs.reference.getBoundingClientRect();
// 实际高度大于或者等于真实高度 说明还没超出
if( height >= realHeight ) {
// 禁用popover
} else {
// 放开popover
}
}
完整代码(需要的直接拿就行)
<template>
<el-popover :disabled="disabled || overflowPopoverDisabled" v-bind="$attrs">
<template slot="reference">
<div
:class="
lineNum == 1
? 'overflow-popover-hidden'
: 'overflow-popover-line-hidden'
"
ref="reference"
:style="`max-width: ${maxWidth}px;${
line != 1 ? `-webkit-line-clamp: ${lineNum}` : ''
}`"
@mouseenter="checkIsShowPopover"
@mouseleave="checkIsShowPopover"
>
<slot />
</div>
</template>
</el-popover>
</template>
<script>
export default {
inheritAttrs: false,
name: "overflowPopover",
data() {
return {
overflowPopoverDisabled: false,
};
},
props: {
// 是否禁用overflowPopover
disabled: {
type: Boolean,
default: false,
},
// 是否进行最大宽度检测 (不做最大宽度检测时,overflowPopover相当普通的Popover组件)
isCheckMaxWidth: {
type: Boolean,
default: true,
},
// 超出隐藏的宽度
maxWidth: {
type: Number,
default: 180,
},
// 针对多行,超出隐藏...的处理
lineNum: {
type: Number,
default: 1,
},
},
methods: {
checkIsShowPopover() {
// 通过获取div节点的getBoundingClientRect属性,拿到div的实际宽度和高度
const { width, height } = this.$refs.reference.getBoundingClientRect();
// 多行的情况下,判断高度不用处理宽度
if (this.lineNum !== 1) {
// scrollHeight 对应的是实际应该渲染的高度,通过比较二者判断是否显示popover
const realHeight = this.$refs.reference.scrollHeight;
this.overflowPopoverDisabled = height >= realHeight;
}
// 只有一行的情况下(无需处理高度)
else if (this.isCheckMaxWidth) {
// 开启最大宽度检测时,比较实际的宽度和我们设置传入的maxWidth。
// 如果没有满足实际小于传入,说明这时候已经出现...隐藏了
this.overflowPopoverDisabled = width < this.maxWidth;
}
},
},
};
</script>
<style scoped>
.overflow-popover-hidden {
display: inline-block;
overflow: hidden;
align-items: center;
text-overflow: ellipsis;
white-space: nowrap;
line-height: normal;
}
.overflow-popover-line-hidden {
display: -webkit-box;
overflow: hidden;
-webkit-box-orient: vertical;
vertical-align: middle;
word-break: break-all;
line-height: normal;
cursor: pointer;
}
</style>
代码文档(overflowPopover组件文档)
Props
| 参数名 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
| maxWidth | number | ❌ | 180 | 最大宽度,超出部分展示省略号,内容超出时指针悬停展示popover |
| lineNum | number | ❌ | 1 | 处理多行省略的情况 |
| isCheckMaxWidth | boolean | ❌ | false | 是否进行最大宽度检测 (不做最大宽度检测时,overflowPopover相当普通的Popover组件) |
| disabled | boolean | ❌ | false | 是否禁用 |
示例
<overflowPopover
width="180"
style="display: inline-flex"
placement="top-start"
trigger="hover"
:content="text"
:maxWidth="120"
><span>{{ text }}</span></overflowPopover
>
实际效果
注意
组件使用了透传,其他的props和elment的Popover props一致