Skip to content

Commit a2bdcd6

Browse files
Elm1992blueSky1992sqchen
authored
feat: ellipsis text automatically displays tooltip based on ellipsis (#6244)
* feat: ellipsis text automatically displays tooltip based on ellipsis * feat: ellipsis text automatically displays tooltip based on ellipsis --------- Co-authored-by: sqchen <[email protected]> Co-authored-by: sqchen <[email protected]>
1 parent 11b2b5b commit a2bdcd6

File tree

3 files changed

+110
-2
lines changed

3 files changed

+110
-2
lines changed

docs/src/components/common-ui/vben-ellipsis-text.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ outline: deep
2626

2727
<DemoPreview dir="demos/vben-ellipsis-text/tooltip" />
2828

29+
## 自动显示 tooltip
30+
31+
通过`tooltip-when-ellipsis`设置,仅在文本长度超出导致省略号出现时才触发 tooltip。
32+
33+
<DemoPreview dir="demos/vben-ellipsis-text/auto-display" />
34+
2935
## API
3036

3137
### Props
@@ -37,6 +43,8 @@ outline: deep
3743
| maxWidth | 文本区域最大宽度 | `number \| string` | `'100%'` |
3844
| placement | 提示浮层的位置 | `'bottom'\|'left'\|'right'\|'top'` | `'top'` |
3945
| tooltip | 启用文本提示 | `boolean` | `true` |
46+
| tooltipWhenEllipsis | 内容超出,自动启用文本提示 | `boolean` | `false` |
47+
| ellipsisThreshold | 设置 tooltipWhenEllipsis 后才生效,文本截断检测的像素差异阈值,越大则判断越严格,如果碰见异常情况可以自己设置阈值 | `number` | `3` |
4048
| tooltipBackgroundColor | 提示文本的背景颜色 | `string` | - |
4149
| tooltipColor | 提示文本的颜色 | `string` | - |
4250
| tooltipFontSize | 提示文本的大小 | `string` | - |
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts" setup>
2+
import { EllipsisText } from '@vben/common-ui';
3+
4+
const text = `
5+
Vben Admin 是一个基于 Vue3.0、Vite、 TypeScript 的后台解决方案,目标是为开发中大型项目提供开箱即用的解决方案。
6+
`;
7+
</script>
8+
<template>
9+
<EllipsisText :line="2" :tooltip-when-ellipsis="true">
10+
{{ text }}
11+
</EllipsisText>
12+
13+
<EllipsisText :line="3" :tooltip-when-ellipsis="true">
14+
{{ text }}
15+
</EllipsisText>
16+
</template>

packages/effects/common-ui/src/components/ellipsis-text/ellipsis-text.vue

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
<script setup lang="ts">
22
import type { CSSProperties } from 'vue';
33
4-
import { computed, ref, watchEffect } from 'vue';
4+
import {
5+
computed,
6+
onBeforeUnmount,
7+
onMounted,
8+
onUpdated,
9+
ref,
10+
watchEffect,
11+
} from 'vue';
512
613
import { VbenTooltip } from '@vben-core/shadcn-ui';
714
@@ -33,6 +40,16 @@ interface Props {
3340
* @default true
3441
*/
3542
tooltip?: boolean;
43+
/**
44+
* 是否只在文本被截断时显示提示框
45+
* @default false
46+
*/
47+
tooltipWhenEllipsis?: boolean;
48+
/**
49+
* 文本截断检测的像素差异阈值,越大则判断越严格
50+
* @default 3
51+
*/
52+
ellipsisThreshold?: number;
3653
/**
3754
* 提示框背景颜色,优先级高于 overlayStyle
3855
*/
@@ -62,12 +79,15 @@ const props = withDefaults(defineProps<Props>(), {
6279
maxWidth: '100%',
6380
placement: 'top',
6481
tooltip: true,
82+
tooltipWhenEllipsis: false,
83+
ellipsisThreshold: 3,
6584
tooltipBackgroundColor: '',
6685
tooltipColor: '',
6786
tooltipFontSize: 14,
6887
tooltipMaxWidth: undefined,
6988
tooltipOverlayStyle: () => ({ textAlign: 'justify' }),
7089
});
90+
7191
const emit = defineEmits<{ expandChange: [boolean] }>();
7292
7393
const textMaxWidth = computed(() => {
@@ -79,9 +99,67 @@ const textMaxWidth = computed(() => {
7999
const ellipsis = ref();
80100
const isExpand = ref(false);
81101
const defaultTooltipMaxWidth = ref();
102+
const isEllipsis = ref(false);
82103
83104
const { width: eleWidth } = useElementSize(ellipsis);
84105
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+
85163
watchEffect(
86164
() => {
87165
if (props.tooltip && eleWidth.value) {
@@ -91,9 +169,13 @@ watchEffect(
91169
},
92170
{ flush: 'post' },
93171
);
172+
94173
function onExpand() {
95174
isExpand.value = !isExpand.value;
96175
emit('expandChange', isExpand.value);
176+
if (props.tooltipWhenEllipsis) {
177+
checkEllipsis();
178+
}
97179
}
98180
99181
function handleExpand() {
@@ -110,7 +192,9 @@ function handleExpand() {
110192
color: tooltipColor,
111193
backgroundColor: tooltipBackgroundColor,
112194
}"
113-
:disabled="!props.tooltip || isExpand"
195+
:disabled="
196+
!props.tooltip || isExpand || (props.tooltipWhenEllipsis && !isEllipsis)
197+
"
114198
:side="placement"
115199
>
116200
<slot name="tooltip">

0 commit comments

Comments
 (0)