vue判断字符串是否溢出来显示弹窗、解决el-table tooltip 内过多导致无法显示,内容闪烁
# vue判断字符串是否溢出来显示弹窗、解决el-table tooltip 内过多导致无法显示,内容闪烁
总体的思路就是获取dom元素,根据dom元素的 clientWidth
与 scrollWidth
来判断是否溢出,我这里正好碰到v-for,所以需要动态绑定每一个元素的ref。
# vue判断字符串是否溢出来显示弹窗
<div v-for="item in items" :key="item.id">
<el-tooltip
:disabled="isOverflow($refs[item.id])"
:content="`${item.content}`"
effect="dark"
placement="top">
<span :ref="item.id">{{ item.content }}</span>
</el-tooltip>
</div>
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 处理函数 isOverflow
const isOverflow = (element) => {
return element ? element[0].clientWidth >= element[0].scrollWidth : false;
}
1
2
3
2
3
# 整理成组件(仅判断字符串是否溢出)
<template>
<el-tooltip
:disabled="disabled"
effect="dark"
:content="tooltipContent || content"
placement="top"
:enterable="false">
<div ref="overflowTooltipContent"
:class="className" class="overflow-content" @mouseover="isOverflow">
{{ content }}
</div>
</el-tooltip>
</template>
<script>
export default {
name: 'overflow-tooltip',
props: {
className: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
tooltipContent: {
type: String,
default: ''
}
},
data() {
return {
disabled: true
};
},
methods: {
isOverflow() {
if (this.$refs.overflowTooltipContent) {
this.disabled = this.$refs.overflowTooltipContent.offsetWidth >= this.$refs.overflowTooltipContent.scrollWidth;
}
}
}
};
</script>
<style lang="scss" scoped>
.overflow-content {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 解决el-table tooltip 内过多导致无法显示,内容闪烁
# 改进:正常显示
后来在el-table遇到了一个问题,就是el-table原本的tooltip,如果内容太多,是显示不下的,而且屏幕会闪烁,盲猜tooltip出现的瞬间鼠标进入了tooltip,表格的tooltip是无法进入,所以马上消失了,然后又显示。
所以我马上用了这个组件,但是加了一些样式,让它溢出的可以滚动。(如果el-table自带的tooltip用这个样式,也可以正常显示,但是鼠标无法进入,所以无法展示所有内容)
不过加了这个样式好像就不能显示arrow了
.popperClass {
max-width: 50vw;
max-height: 50vh;
overflow-y: auto;
}
1
2
3
4
5
2
3
4
5
# 改进:自动判断鼠标是否需要移入
鼠标移入后,获取popper节点,判断el-tooltip的内容是否溢出,如果溢出,才允许鼠标进入。
setTimeout(() => {
const popper = this.$refs.tooltip.$refs.popper;
if (popper) {
this.autoEnter = popper.offsetHeight < popper.scrollHeight;
}
}, 100);
1
2
3
4
5
6
2
3
4
5
6
# 改进:结构改为div包着span,和原来el-table的样子差不多
这时候需要修改一下原先判断溢出的方法。
const el = this.$refs.overflowTooltipContent;
if (el) {
const parent = el.parentNode;
this.disabled = parent.offsetWidth >= el.offsetWidth;
}
1
2
3
4
5
2
3
4
5
# 最终的组件
<template>
<el-tooltip
ref="tooltip"
:disabled="disabled"
effect="dark"
:content="tooltipContent || content"
:placement="placement"
:enterable="autoEnter === null ? enterable : autoEnter"
:popper-class="popperClass"
:visible-arrow="false"
>
<div class="overflow-content-wrapper">
<span
ref="overflowTooltipContent"
class="overflow-content"
:class="className"
@mouseover="isOverflow"
>{{ content }}</span>
</div>
</el-tooltip>
</template>
<script>
export default {
name: 'OverflowTooltip',
props: {
className: {
type: String,
default: ''
},
content: {
type: String,
default: ''
},
tooltipContent: {
type: String,
default: ''
},
enterable: {
type: Boolean,
default: false
},
autoEnterable: {
type: Boolean,
default: false
},
popperClass: {
type: String,
default: ''
},
placement: {
type: String,
default: 'top'
}
},
data() {
return {
disabled: true,
autoEnter: null
};
},
methods: {
isOverflow() {
const el = this.$refs.overflowTooltipContent;
if (el) {
const parent = el.parentNode;
this.disabled = parent.offsetWidth >= el.offsetWidth;
}
if (this.autoEnterable) {
setTimeout(() => {
const popper = this.$refs.tooltip.$refs.popper;
if (popper) {
this.autoEnter = popper.offsetHeight < popper.scrollHeight;
}
}, 100);
}
}
}
};
</script>
<style scoped>
.overflow-content-wrapper {
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.overflow-content {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# Vue3 + TS 组件重新封装,支持多行省略
element-plus好像不会出现超多内容闪烁,el-tooltip会自动撑开整个页面,所以这里只是在第一个组件的基础上增加了传入参数就可以支持多行省略。
<template>
<el-tooltip
ref="tooltipRef"
effect="dark"
:disabled="disabled"
:content="tooltipContent || content"
>
<span
ref="contentRef"
class="overflow-content"
:class="[{'overflow-line-clamp': lineClamp}, className]"
:style="{'--line-clamp': lineClamp}"
@mouseover="isOverflow"
>{{ content }}</span>
</el-tooltip>
</template>
<script setup lang="ts">
import type { ElTooltip } from 'element-plus/es';
const props = defineProps<{
content: string;
className?: string;
lineClamp?: number;
tooltipContent?: string;
}>();
const tooltipRef = ref<InstanceType<typeof ElTooltip>>();
const contentRef = ref<HTMLSpanElement>();
const disabled = ref(true);
const isOverflow = () => {
const el = contentRef.value;
if (el) {
if (props.lineClamp) {
disabled.value = el.offsetHeight >= el.scrollHeight;
} else {
disabled.value = el.offsetWidth >= el.scrollWidth;
}
}
};
</script>
<style lang="scss" scoped>
.overflow-content {
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.overflow-line-clamp {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
white-space: pre-wrap;
-webkit-line-clamp: var(--line-clamp, 2);
-webkit-box-orient: vertical;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
上次更新: 2023/06/01, 12:40:50