问题描述
项目中经常会遇到文字超长,超出之后需要显示省略号和el-tooltip
的情况。
简单粗暴的方法就是统一显示tooltip,不管是否有显示省略号,但是这样显然不太友好。
最好的办法就是在显示省略号的时候,才显示tooltip。
那么,如何知道是否显示了省略号呢?
问题分析
方案一
最先想到的方法是,根据宽度来计算最多容纳文字的个数,如果实际文字的个数有超过这个最大个数,则显示tooltip。
但是这个问题也很严重,首先英文和中文的长度是不一样的,而且还有可能有特殊符号,而且如果屏幕有了缩放,那就更不准确了,所以这种方案很快就pass了。
方案二
也就是现在使用的方案,通过判断当前文本的offsetWidth
和scrollWidth
,来确定是否显示tooltip,这种准确性就很可靠了,scrollWidth是文本实际的宽度不会因为显示了省略号而变化。
方案三
与方案二类似,不过比较的是文本的scrollWidth
和其父元素的clientWidth
,如果文本的scrollWidth大于其父元素的clientWidth,则显示tooltip。
具体代码实现
代码中除了单行文字超出显示省略号好tooltip之外,还加入了多行显示省略号好tooltip功能,主要是根据css属性-webkit-line-clamp
来操作的。
多行显示tooltip的依据是dom.offsetHeight < dom.scrollHeight
,也就是说,多行显示省略号后,其scrollHeight
是不变的,类似scrollWidth
,所以可以作为判断依据。
为了方便使用,本来想封装成自定义指令的形式,但是奈何el-tooltip不支持js调用的形式,所以只能封装成一个组件代码BaseElliTip.vue
,代码如下:
<script lang="ts" setup>
/**
* desc: 文本超出显示省略号,并且显示tooltip
* feat:支持自定义多行显示省略
* usage:
* 1、<BaseElliTip>显示文本</BaseElliTip>
* 2、<BaseElliTip text="显示文本"></BaseElliTip>
* 3、<BaseElliTip content="显示文本">显示文本</BaseElliTip>
* 4、<BaseElliTip :lineNumber="3">显示文本</BaseElliTip>
*/
import {computed, ref} from "vue";
interface IProps {
// 显示内容
text?: string,
// 显示位置
placement?: string,
// tip内容
content?: string,
// 要显示的行数
lineNumber: number
}
const prop = withDefaults(defineProps<IProps>(), {
placement: 'top',
lineNumber: 1
})
let showTooltip = ref(true);
function onMouseEnter(e) {
const dom = e.target;
console.log(dom.getBoundingClientRect().width, dom.clientWidth, dom.offsetWidth, dom.scrollWidth, dom.parentElement.offsetWidth)
console.log(dom.offsetHeight, dom.scrollHeight)
// 单行会比较 dom.offsetWidth < dom.scrollWidth
// 多行会比较 dom.offsetHeight < dom.scrollHeight
showTooltip.value = !(dom.offsetWidth < dom.scrollWidth || dom.offsetHeight < dom.scrollHeight);
}
</script>
<template>
<el-tooltip class="elli-tip-box" v-bind="$attrs" :disabled="showTooltip" :placement="placement">
<template #content>
<span v-if="content || text">{ { content || text } }</span>
<span v-else><slot></slot></span>
</template>
<div :class="lineNumber>1 ? 'text-ellipsis-multiple' : 'truncate'" @mouseenter.stop="onMouseEnter">
<slot>{ { text } }</slot>
</div>
</el-tooltip>
</template>
<style lang="less" scoped>
//多行文本文字超过行数限制后显示省略号
// caniuse兼容性(不支持IE):https://caniuse.com/?search=-webkit-line-clamp
.text-ellipsis-multiple {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -moz-box;
display: -webkit-box;
display: -ms-flexbox;
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-webkit-line-clamp: v-bind('prop.lineNumber');
}
</style>
-webkit-line-clamp
属性的兼容性还是不错的,除了IE之外,主流浏览器基本都支持。