目录
应用场景:
项目中很多地方需要显示一些字段信息,比如项目信息,项目说明的字段,总会有需求是显示当字段内容过多的时候,加省略号显示,然后显示tooltip,这个功能在el-table里好实现,只是需要show-overflow-tooltip就可以实现,因为很多地方需要用到,所以对这个功能进行了封装,有两种实现方式,适配elementUI和element-plus。先看最后!
父组件:
既然是封装,先新建一个文件,比如:ToolTip.vue,作为封装的页面,再在父组件中引入这个组件,引入需要一些信息,既然是封装的tooltip,那么肯定需要tooltip的content,朝向,还有ref的name,方便区分。如下,父组件最好在外层有一个样式,方便固定宽度。
<div class="title">
<ToolTip :content="projectName" placement="bottom" ref-name="tooltipOver"></ToolTip>
</div>
子组件:
el-tooltip有一个属性disabled,通过判断内容是否需要显示省略号来决定是否禁用这个tooltip。
全部代码如下:
<template>
<div class="text-tooltip">
<el-tooltip class="text-truncate" effect="dark" :disabled="isShowTooltip" :content="content" placement="top">
<p class="over-flow" :class="className" @mouseover="onMouseOver(refName)">
<span :ref="refName" class="ellipsis">{
{ content || '' }}</span>
</p>
</el-tooltip>
</div>
</template>
<script>
export default {
name: 'textTooltip',
props: {
// 显示的文字内容
content: {
type: String,
default: () => {
return ''
}
},
// 外层框的样式,在传入的这个类名中设置文字显示的宽度
className: {
type: String,
default: () => {
return ''
}
},
// 为页面文字标识(如在同一页面中调用多次组件,此参数不可重复)
refName: {
type: String,
default: () => {
return ''
}
}
},
data() {
return {
isShowTooltip: true
}
},
mounted() {
//判断宽度是否需要出现toooltip
this.checkTooltipVisibility()
//优化resize
window.addEventListener('resize', this.checkTooltipVisibility)
},
beforeUnmount() {
window.removeEventListener('resize', this.checkTooltipVisibility)
},
methods: {
onMouseOver(refName) {
//这里的refName是子组件的refName不是从父组件传来的,所以需要在@mouseover里传递,使得页面能找到这个dom
let parentWidth = this.$refs[refName].parentNode.offsetWidth
let contentWidth = this.$refs[refName].offsetWidth
// 判断是否开启tooltip功能
if (contentWidth > parentWidth) {
this.isShowTooltip = false
} else {
this.isShowTooltip = true
}
},
checkTooltipVisibility() {
const spanEl = this.$refs[this.refName]
if (spanEl) {
const parentWidth = spanEl.parentNode.offsetWidth
const contentWidth = spanEl.offsetWidth
this.isShowTooltip = contentWidth > parentWidth
}
}
}
}
</script>
<style lang="scss" scoped>
.over-flow {
overflow: hidden;
white-space: nowrap;
width: 100%; /* 设置父元素的宽度 */
}
.ellipsis {
width: 100%; /* 设置子元素的宽度,确保父元素的宽度能容纳子元素*/
white-space: nowrap; /* 不换行 */
overflow: hidden; /* 溢出隐藏 */
text-overflow: ellipsis; /* 添加省略号 */
}
//这里还可以将外层的className对应的class写在这里
p {
margin: 0;
}
</style>
注意:当应用样式 .over-flow
的父元素的宽度不足以容纳子元素时,子元素的溢出部分将被隐藏,省略号也可能无法显示出来。这也是我之前一直修改但是样式依旧无法呈现的原因,后来将子元素和父元素的宽度设置了100%(具体值也可以)就成功了,实现效果如下:
element细节如下,如果不生效可以看看是否和我出现的问题一致。
这样就实现了当页面宽度变化的时候也能重新计算然后显示省略号或者不显示。
当然计算dom的宽度是一个方法,也可以通过计算content的内容长度,比如有多少个字符这种简答的方式来显示(之前一直用的这种方法,在某些地方还不得不继续用,那里没有固定的宽度)
前者这种方法显然更好一点,这种方法在element-ui里可以将span换成el-text,比较省事,不用考虑样式问题,如下:
<span :ref="refName" class="ellipsis">{
{ content || '' }}</span>
//换成el-text
<el-text :ref="refName" truncated>{
{ content || '' }}</el-text>
但是!element-plus依旧废弃了el-text,页面解析不出来这个组件,打包后页面也会无法显示省略号!
bug:
当天发现写完这个组件,并不能显示tooltip,原因很简单,最里层的span并不能溢出<p>的宽度,所以根据这种情况,我需要满足两个需求:
1是子元素需要能宽度溢出父元素,
2是溢出时显示tooltip(计算得出的溢出,那么需要子元素的宽度大于父元素)和省略号
先看2,要求显示省略号,那么就需要子元素的宽度比较在父元素的宽度内,代码里也提及这一点,但是我需要满足1需求,所以两个需求冲突。
解决方案1:更改样式,当组件初始化的时候,先将样式改为不能溢出但显示省略号的样式1(上文提及的样式),当鼠标移上去的时候改为宽度能溢出的样式2,鼠标移出时,再改为样式1
<template>
<div class="text-tooltip">
<el-tooltip class="item" effect="dark" :disabled="isShowTooltip" :content="content" placement="top">
<div class="over-flow" :class="className" @mouseover="onMouseOver(refName)" @mouseout="onMouseOut(refName)">
<span :ref="refName" class="ellipsis">{
{ content || '' }}</span>
</div>
</el-tooltip>
</div>
</template>
methods: {
onMouseOver(refName) {
//更换样式为子元素可以溢出父元素的样式
this.$refs[refName].style.removeProperty('width')
this.$refs[refName].style.overflow = 'visible'
this.$refs[refName].style.whiteSpace = 'nowrap'
this.$refs[refName].style.textOverflow = 'ellipsis'
this.$refs[refName].parentNode.style.overflow = 'hidden'
this.$refs[refName].parentNode.style.width = '100%'
let parentWidth = this.$refs[refName].parentNode.offsetWidth
let contentWidth = this.$refs[refName].offsetWidth
// 判断是否开启tooltip功能
this.isShowTooltip = true
}
},
onMouseOut(refName) {
// 重置样式为省略文本
this.$refs[refName].style.overflow = 'hidden'
this.$refs[refName].style.width = '100%'
this.$refs[refName].style.whiteSpace = 'nowrap'
this.$refs[refName].style.textOverflow = 'ellipsis'
this.$refs[refName].parentNode.style.overflow = 'visible'
this.$refs[refName].parentNode.style.width = '100%'
},
checkTooltipVisibility() {
const spanEl = this.$refs[this.refName]
if (spanEl) {
//初始样式为省略文本
this.onMouseOut(this.refName)
const parentWidth = spanEl.parentNode.offsetWidth
const contentWidth = spanEl.offsetWidth
if (contentWidth > parentWidth) {
this.isShowTooltip = false
} else {
this.isShowTooltip = true
}
}
}
}
<style lang="scss" scoped>
//初始的省略显示
.over-flow {
overflow: visible; /* 溢出隐藏 */
white-space: nowrap;
width: 100%; /* 设置父元素的宽度 */
}
.ellipsis {
// width: 100%; /* 设置子元素的宽度,确保父元素的宽度能容纳子元素*/
white-space: nowrap; /* 不换行 */
overflow: hidden; /* 可以溢出 */
text-overflow: ellipsis; /* 添加省略号 */
}
div {
margin: 0;
}
解决方案2:直接不计算,全部显示tooltip,这样省事,span显示样式1
<el-tooltip class="item" effect="dark" :disabled="!isShowTooltip" :content="content" placement="top">
<div class="over-flow" :class="className">
<span :ref="refName" class="ellipsis">{
{ content || '' }}</span>
</div>
</el-tooltip>
<style lang="scss" scoped>
//初始的省略显示
.over-flow {
overflow: hidden; /* 溢出隐藏 */
white-space: nowrap;
width: 100%; /* 设置父元素的宽度 */
}
.ellipsis {
width: 100%; /* 设置子元素的宽度,确保父元素的宽度能容纳子元素*/
white-space: nowrap; /* 不换行 */
overflow: hidden; /* 溢出隐藏 */
text-overflow: ellipsis; /* 添加省略号 */
}
综上。实在不知道有没有其他好解决的方案,有知道的大佬评论区能指导一下吗?