Vant TextEllipsis 组件实战指南:长文本省略、展开/收起与自定义省略位置
2026/9/13 12:30:03 网站建设 项目流程

Vant TextEllipsis 组件实战指南:长文本省略、展开/收起与自定义省略位置

【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant

本指南以 Vant 移动端组件库中的TextEllipsis组件为对象,系统讲解如何在 Vue 3 项目中实现长文本的多行省略、展开/收起交互,以及从头/中/尾三个位置自定义省略方式。读完本文,你将掌握该组件的全部 Props、事件、实例方法、插槽与主题变量,并能基于源码理解其基于 DOM 克隆与二分查找的省略文本计算原理。

组件定位与引入

TextEllipsis是 Vant 提供的一个轻量文本省略组件,用于对超长文本进行省略展示,并原生支持展开/收起交互。该组件从vant >= v4.1.0版本开始提供,请在使用前确认依赖版本满足要求(dots属性自v4.2.0起可用,position属性自v4.6.2起可用,action插槽自v4.8.3起可用)。

组件的源码位于 packages/vant/src/text-ellipsis/TextEllipsis.tsx,入口文件 packages/vant/src/text-ellipsis/index.ts 通过withInstall将其包装为可全局注册的插件形式,同时声明了VanTextEllipsis全局组件类型:

declare module 'vue' { export interface GlobalComponents { VanTextEllipsis: typeof TextEllipsis; } }

注册组件

推荐通过app.use全局注册,也可以按需引入(按需引入会自动注册样式):

import { createApp } from 'vue'; import { TextEllipsis } from 'vant'; const app = createApp(); app.use(TextEllipsis);

关于组件注册的更多方式(如局部注册、自动按需导入),可参考 组件注册文档。

基础用法:单行省略

不传任何配置时,组件默认展示 1 行,超长内容尾部以省略号...截断:

<van-text-ellipsis :content="text" />
export default { setup() { const text = 'Take your time and be patient. Life itself will eventually answer all those questions it once raised for you.'; return { text }; }, };

当内容未超过设定行数时,组件不会渲染省略号与操作按钮,这一点由源码中的高度对比逻辑保证(详见下文「源码原理」一节),对应的测试用例text not exceeded也验证了短文本不会出现...(见 test/index.spec.tsx)。

展开/收起

通过expand-textcollapse-text两个属性分别指定「展开」与「收起」操作文案,点击后即可在完整文本与省略文本之间切换:

<van-text-ellipsis :content="text" expand-text="expand" collapse-text="collapse" />
export default { setup() { const text = "The fleeting time of one's life is everything that belongs to a person. Only this thing truly belongs to you. Everything else is just a momentary pleasure or misfortune, which will soon be gone with the passing of time."; return { text }; }, };

展开/收起状态的切换由实例方法toggle驱动:点击操作区会调用toggle()取反展开状态,同时触发click-action事件(事件参数为原生MouseEvent)。

自定义展示行数

通过rows属性控制省略前展示的行数,属性值支持数字或字符串:

<van-text-ellipsis rows="3" :content="text" expand-text="expand" collapse-text="collapse" />
export default { setup() { const text = "That day, I turned twenty-one. In the golden age of my life, I was full of dreams. I wanted to love, to eat, and to instantly transform into one of these clouds, part alight, part darkened. It was only later that I understood life is but a slow, drawn-out process of getting your balls crushed. Day by day, you get older. Day by day, your dreams fade. In the end you are no different from a crushed ox. But I hadn't foreseen any of it on my twenty-first birthday. I thought I would be vigorous forever, and that nothing could ever crush me."; return { text }; }, };

自定义省略位置

默认情况下省略发生在文本尾部position="end")。position属性支持startmiddle两个取值,分别实现「头部省略」与「中部省略」:

头部省略(position="start")

省略号出现在文本开头,保留结尾部分:

<van-text-ellipsis rows="1" :content="text" expand-text="expand" collapse-text="collapse" position="start" />

中部省略(position="middle")

省略号出现在文本中间,同时保留开头与结尾部分:

<van-text-ellipsis rows="2" :content="text" expand-text="expand" collapse-text="collapse" position="middle" />

提示:middle位置在计算时对文本左右两侧分别做二分逼近,从而找到「前后各保留多少字符」的精确切分点,具体实现见下文「源码原理」中的middleTail函数。

自定义操作内容(action 插槽)

默认操作区渲染的是expand-text/collapse-text文本。若需要自定义按钮样式或文案(例如带图标的按钮),可使用action插槽,插槽作用域暴露{ expanded: boolean },用于区分当前是展开态还是收起态:

<van-text-ellipsis :content="text"> <template #action="{ expanded }"> {{ expanded ? 'Collapse' : 'Expand' }} </template> </van-text-ellipsis>
export default { setup() { const text = 'Take your time and be patient. Life itself will eventually answer all those questions it once raised for you.'; return { text }; }, };

需要说明的是:只有内容确实超出rows指定行数时,操作区才会被渲染(由hasAction状态控制)。此外,当使用action插槽时,源码会在组件挂载后额外执行一次nextTick(calcEllipsised)重算,原因是插槽内容(操作按钮)本身也占用高度,需要将其计入省略计算。测试用例should render action slot correctly对该行为做了快照验证(见 test/index.spec.tsx)。

API 总览

Props

属性说明类型默认值
rows展示的行数number | string1
content展示的文本内容string-
expand-text展开操作文案string-
collapse-text收起操作文案string-
dotsv4.2.0省略号文本内容string'...'
positionv4.6.2省略位置,可选startmiddlestring'end'

源码中这些属性的默认值定义在 TextEllipsis.tsx:

export const textEllipsisProps = { rows: makeNumericProp(1), dots: makeStringProp('...'), content: makeStringProp(''), expandText: makeStringProp(''), collapseText: makeStringProp(''), position: makeStringProp('end'), };

其中rows使用makeNumericProp包装,因此同时接受数字与字符串;dots可自定义省略号文本(如'……')。

Events

事件说明回调参数
click-action点击展开/收起时触发event: MouseEvent

对应测试用例should emit click event after Expand/Collapse is clicked验证了点击操作区会恰好触发一次该事件(见 test/index.spec.tsx)。

Methods

通过ref获取组件实例后调用:

名称说明参数返回值
toggle切换展开状态expanded?: boolean-

toggle支持传入目标状态(true展开 /false收起),不传参时自动取反当前状态:

const toggle = (isExpanded = !expanded.value) => { expanded.value = isExpanded; };

该方法通过useExpose暴露到组件实例上(见 TextEllipsis.tsx),TSX 测试中即通过(wrapper.vm as TextEllipsisInstance).toggle()驱动状态切换。

Slots

名称说明插槽参数
actionv4.8.3自定义操作内容{ expanded: boolean }

Types

组件导出以下类型定义,便于在 TypeScript 项目中获得完整的类型提示:

import type { TextEllipsisProps, TextEllipsisInstance, TextEllipsisThemeVars, } from 'vant';

TextEllipsisInstance为组件实例类型,配合ref使用toggle方法:

import { ref } from 'vue'; import type { TextEllipsisInstance } from 'vant'; const textEllipsisRef = ref<TextEllipsisInstance>(); textEllipsisRef.value?.toggle();

类型定义位于 types.ts:TextEllipsisInstanceComponentPublicInstance<TextEllipsisProps, TextEllipsisExpose>构造,TextEllipsisThemeVars声明了textEllipsisActionColor主题变量。

主题定制:CSS 变量

组件提供以下 CSS 变量,可用于自定义样式。全局主题定制可配合 ConfigProvider 组件 使用:

名称默认值说明
--van-text-ellipsis-action-colorvar(--van-blue)操作文字颜色
--van-text-ellipsis-line-height1.6文本行高

对应的样式定义在 index.less:

:root, :host { --van-text-ellipsis-line-height: 1.6; --van-text-ellipsis-action-color: var(--van-blue); } .van-text-ellipsis { line-height: var(--van-text-ellipsis-line-height); white-space: pre-wrap; overflow-wrap: break-word; &__action { cursor: pointer; color: var(--van-text-ellipsis-action-color); &:active { opacity: var(--van-active-opacity); } } }

值得注意的是,文本容器使用了white-space: pre-wrap,因此组件会保留内容中的换行符;line-height变量不仅影响视觉,还直接参与省略计算(见下文),因此修改行高变量后组件会自动适配截断结果。

源码原理:基于 DOM 克隆与二分查找的省略计算

理解TextEllipsis的实现,有助于预判它在复杂布局(如动态字体、容器尺寸变化、KeepAlive 缓存)下的行为。核心计算流程全部位于 TextEllipsis.tsx:

1. 克隆容器进行无痕测量

组件并不直接修改真实 DOM,而是将根节点的完整计算样式拷贝到一个position: fixed; top: -9999px; z-index: -9999的隐藏容器中(cloneContainer),把content文本塞入后追加到document.body,在不可见区域完成高度测量,测量结束后立即移除。这样既不影响页面布局,又能精确复现真实渲染行高。

2. 计算最大允许高度

calcEllipsised中,最大高度按行数换算:

const maxHeight = Math.ceil( (Number(props.rows) + 0.5) * pxToNum(lineHeight) + pxToNum(paddingTop) + pxToNum(paddingBottom), );

(rows + 0.5)倍行高再加上上下内边距。pxToNum负责把lineHeightpx字符串解析为数字。当maxHeight < container.offsetHeight时判定内容超行,执行省略计算并渲染操作区;否则直接展示完整文本、不渲染操作区。

3. 二分查找精确截断点

尾部省略(position="end")使用二分逼近(calcEllipse中的tail函数):不断尝试「保留前 middle 个字符 + 省略号」,若高度仍超过maxHeight则向左收缩,否则向右扩张,最终收敛到满足高度约束的最大保留长度,保证省略号后不会出现被截断的半行字符。头部省略(position="start")逻辑对称,保留的是文本尾部。

4. 中部省略的双侧逼近

中部省略(position="middle")由middleTail函数实现:以文本中点为中心,对左半部分与右半部分同时做二分收缩(左侧收缩用floor、右侧用ceil),直到拼接后的「左段 + 省略号 + 右段」高度恰好满足约束,从而最大化保留开头与结尾的有效信息。

5. 响应式重算与 KeepAlive 适配

组件对windowWidth(来自 utils/dom.ts 的useWindowSize)以及contentrowsposition的变化做了watch,尺寸或配置变化时自动重算省略文本。针对 KeepAlive 缓存场景(对应 vant-ui/vant#12445 提到的问题),组件在onActivated钩子中检查needRecalculate标记并重新计算——当挂载时容器尚未连接(!root.value.isConnected)会导致测量失败,此时延迟到组件被激活时再补齐计算,保证被 KeepAlive 缓存的页面恢复显示时省略状态依然正确(见 test/index.spec.tsx 中的对应测试)。

总结

TextEllipsis以极简的 API 覆盖了移动端长文本展示的核心诉求:默认单行省略、多行截断、头/中/尾三种省略位置、内置展开收起与自定义插槽,并通过 CSS 变量保持与 Vant 主题体系一致。在源码层面,它以「隐藏克隆容器测量 + 二分查找」的方式计算截断文本,兼顾了精度与性能,同时对窗口尺寸变化与 KeepAlive 激活场景做了针对性处理。若要深入了解完整 API 与示例,可继续阅读组件文档 README.zh-CN.md 与演示代码 demo/index.vue。

【免费下载链接】vantA lightweight, customizable Vue UI library for mobile web apps.项目地址: https://gitcode.com/GitHub_Trending/va/vant

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询