ellipsis-text.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. <script setup lang="ts">
  2. import type { CSSProperties } from 'vue';
  3. import { computed, ref, watchEffect } from 'vue';
  4. import { VbenTooltip } from '@vben-core/shadcn-ui';
  5. import { useElementSize } from '@vueuse/core';
  6. interface Props {
  7. /**
  8. * 是否启用点击文本展开全部
  9. * @default false
  10. */
  11. expand?: boolean;
  12. /**
  13. * 文本最大行数
  14. * @default 1
  15. */
  16. line?: number;
  17. /**
  18. * 文本最大宽度
  19. * @default '100%'
  20. */
  21. maxWidth?: number | string;
  22. /**
  23. * 提示框位置
  24. * @default 'top'
  25. */
  26. placement?: 'bottom' | 'left' | 'right' | 'top';
  27. /**
  28. * 是否启用文本提示框
  29. * @default true
  30. */
  31. tooltip?: boolean;
  32. /**
  33. * 提示框背景颜色,优先级高于 overlayStyle
  34. */
  35. tooltipBackgroundColor?: string;
  36. /**
  37. * 提示文本字体颜色,优先级高于 overlayStyle
  38. */
  39. tooltipColor?: string;
  40. /**
  41. * 提示文本字体大小,单位px,优先级高于 overlayStyle
  42. */
  43. tooltipFontSize?: number;
  44. /**
  45. * 提示框内容最大宽度,单位px,默认不设置时,提示文本内容自动与展示文本宽度保持一致
  46. */
  47. tooltipMaxWidth?: number;
  48. /**
  49. * 提示框内容区域样式
  50. * @default { textAlign: 'justify' }
  51. */
  52. tooltipOverlayStyle?: CSSProperties;
  53. }
  54. const props = withDefaults(defineProps<Props>(), {
  55. expand: false,
  56. line: 1,
  57. maxWidth: '100%',
  58. placement: 'top',
  59. tooltip: true,
  60. tooltipBackgroundColor: '',
  61. tooltipColor: '',
  62. tooltipFontSize: 14,
  63. tooltipMaxWidth: undefined,
  64. tooltipOverlayStyle: () => ({ textAlign: 'justify' }),
  65. });
  66. const emit = defineEmits<{ expandChange: [boolean] }>();
  67. const textMaxWidth = computed(() => {
  68. if (typeof props.maxWidth === 'number') {
  69. return `${props.maxWidth}px`;
  70. }
  71. return props.maxWidth;
  72. });
  73. const ellipsis = ref();
  74. const isExpand = ref(false);
  75. const defaultTooltipMaxWidth = ref();
  76. const { width: eleWidth } = useElementSize(ellipsis);
  77. watchEffect(
  78. () => {
  79. if (props.tooltip && eleWidth.value) {
  80. defaultTooltipMaxWidth.value =
  81. props.tooltipMaxWidth ?? eleWidth.value + 24;
  82. }
  83. },
  84. { flush: 'post' },
  85. );
  86. function onExpand() {
  87. isExpand.value = !isExpand.value;
  88. emit('expandChange', isExpand.value);
  89. }
  90. function handleExpand() {
  91. props.expand && onExpand();
  92. }
  93. </script>
  94. <template>
  95. <div>
  96. <VbenTooltip
  97. :content-style="{
  98. ...tooltipOverlayStyle,
  99. maxWidth: `${defaultTooltipMaxWidth}px`,
  100. fontSize: `${tooltipFontSize}px`,
  101. color: tooltipColor,
  102. backgroundColor: tooltipBackgroundColor,
  103. }"
  104. :disabled="!props.tooltip || isExpand"
  105. :side="placement"
  106. >
  107. <slot name="tooltip">
  108. <slot></slot>
  109. </slot>
  110. <template #trigger>
  111. <div
  112. ref="ellipsis"
  113. :class="{
  114. '!cursor-pointer': expand,
  115. ['block truncate']: line === 1,
  116. [$style.ellipsisMultiLine]: line > 1,
  117. }"
  118. :style="{
  119. '-webkit-line-clamp': isExpand ? '' : line,
  120. 'max-width': textMaxWidth,
  121. }"
  122. class="cursor-text overflow-hidden"
  123. @click="handleExpand"
  124. v-bind="$attrs"
  125. >
  126. <slot></slot>
  127. </div>
  128. </template>
  129. </VbenTooltip>
  130. </div>
  131. </template>
  132. <style module>
  133. .ellipsisMultiLine {
  134. display: -webkit-box;
  135. -webkit-box-orient: vertical;
  136. }
  137. </style>