1
1
<script setup lang="ts">
2
2
import type { CSSProperties } from ' vue' ;
3
3
4
- import { computed , ref , watchEffect } from ' vue' ;
4
+ import {
5
+ computed ,
6
+ onBeforeUnmount ,
7
+ onMounted ,
8
+ onUpdated ,
9
+ ref ,
10
+ watchEffect ,
11
+ } from ' vue' ;
5
12
6
13
import { VbenTooltip } from ' @vben-core/shadcn-ui' ;
7
14
@@ -33,6 +40,16 @@ interface Props {
33
40
* @default true
34
41
*/
35
42
tooltip? : boolean ;
43
+ /**
44
+ * 是否只在文本被截断时显示提示框
45
+ * @default false
46
+ */
47
+ tooltipWhenEllipsis? : boolean ;
48
+ /**
49
+ * 文本截断检测的像素差异阈值,越大则判断越严格
50
+ * @default 3
51
+ */
52
+ ellipsisThreshold? : number ;
36
53
/**
37
54
* 提示框背景颜色,优先级高于 overlayStyle
38
55
*/
@@ -62,12 +79,15 @@ const props = withDefaults(defineProps<Props>(), {
62
79
maxWidth: ' 100%' ,
63
80
placement: ' top' ,
64
81
tooltip: true ,
82
+ tooltipWhenEllipsis: false ,
83
+ ellipsisThreshold: 3 ,
65
84
tooltipBackgroundColor: ' ' ,
66
85
tooltipColor: ' ' ,
67
86
tooltipFontSize: 14 ,
68
87
tooltipMaxWidth: undefined ,
69
88
tooltipOverlayStyle : () => ({ textAlign: ' justify' }),
70
89
});
90
+
71
91
const emit = defineEmits <{ expandChange: [boolean ] }>();
72
92
73
93
const textMaxWidth = computed (() => {
@@ -79,9 +99,67 @@ const textMaxWidth = computed(() => {
79
99
const ellipsis = ref ();
80
100
const isExpand = ref (false );
81
101
const defaultTooltipMaxWidth = ref ();
102
+ const isEllipsis = ref (false );
82
103
83
104
const { width : eleWidth } = useElementSize (ellipsis );
84
105
106
+ // 检测文本是否被截断
107
+ const checkEllipsis = () => {
108
+ if (! ellipsis .value || ! props .tooltipWhenEllipsis ) return ;
109
+
110
+ const element = ellipsis .value ;
111
+
112
+ const originalText = element .textContent || ' ' ;
113
+ const originalTrimmed = originalText .trim ();
114
+
115
+ // 对于空文本直接返回 false
116
+ if (! originalTrimmed ) {
117
+ isEllipsis .value = false ;
118
+ return ;
119
+ }
120
+
121
+ const widthDiff = element .scrollWidth - element .clientWidth ;
122
+ const heightDiff = element .scrollHeight - element .clientHeight ;
123
+
124
+ // 使用足够大的差异阈值确保只有真正被截断的文本才会显示 tooltip
125
+ isEllipsis .value =
126
+ props .line === 1
127
+ ? widthDiff > props .ellipsisThreshold
128
+ : heightDiff > props .ellipsisThreshold ;
129
+ };
130
+
131
+ // 使用 ResizeObserver 监听尺寸变化
132
+ let resizeObserver: null | ResizeObserver = null ;
133
+
134
+ onMounted (() => {
135
+ if (typeof ResizeObserver !== ' undefined' && props .tooltipWhenEllipsis ) {
136
+ resizeObserver = new ResizeObserver (() => {
137
+ checkEllipsis ();
138
+ });
139
+
140
+ if (ellipsis .value ) {
141
+ resizeObserver .observe (ellipsis .value );
142
+ }
143
+ }
144
+
145
+ // 初始检测
146
+ checkEllipsis ();
147
+ });
148
+
149
+ // 使用onUpdated钩子检测内容变化
150
+ onUpdated (() => {
151
+ if (props .tooltipWhenEllipsis ) {
152
+ checkEllipsis ();
153
+ }
154
+ });
155
+
156
+ onBeforeUnmount (() => {
157
+ if (resizeObserver ) {
158
+ resizeObserver .disconnect ();
159
+ resizeObserver = null ;
160
+ }
161
+ });
162
+
85
163
watchEffect (
86
164
() => {
87
165
if (props .tooltip && eleWidth .value ) {
@@ -91,9 +169,13 @@ watchEffect(
91
169
},
92
170
{ flush: ' post' },
93
171
);
172
+
94
173
function onExpand() {
95
174
isExpand .value = ! isExpand .value ;
96
175
emit (' expandChange' , isExpand .value );
176
+ if (props .tooltipWhenEllipsis ) {
177
+ checkEllipsis ();
178
+ }
97
179
}
98
180
99
181
function handleExpand() {
@@ -110,7 +192,9 @@ function handleExpand() {
110
192
color: tooltipColor,
111
193
backgroundColor: tooltipBackgroundColor,
112
194
}"
113
- :disabled =" !props.tooltip || isExpand"
195
+ :disabled ="
196
+ !props.tooltip || isExpand || (props.tooltipWhenEllipsis && !isEllipsis)
197
+ "
114
198
:side =" placement"
115
199
>
116
200
<slot name =" tooltip" >
0 commit comments