
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 :contenttext /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-text与collapse-text两个属性分别指定「展开」与「收起」操作文案点击后即可在完整文本与省略文本之间切换van-text-ellipsis :contenttext expand-textexpand collapse-textcollapse /export default { setup() { const text The fleeting time of ones 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 rows3 :contenttext expand-textexpand collapse-textcollapse /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 hadnt 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 }; }, };自定义省略位置默认情况下省略发生在文本尾部positionend。position属性支持start与middle两个取值分别实现「头部省略」与「中部省略」头部省略positionstart省略号出现在文本开头保留结尾部分van-text-ellipsis rows1 :contenttext expand-textexpand collapse-textcollapse positionstart /中部省略positionmiddle省略号出现在文本中间同时保留开头与结尾部分van-text-ellipsis rows2 :contenttext expand-textexpand collapse-textcollapse positionmiddle /提示middle位置在计算时对文本左右两侧分别做二分逼近从而找到「前后各保留多少字符」的精确切分点具体实现见下文「源码原理」中的middleTail函数。自定义操作内容action 插槽默认操作区渲染的是expand-text/collapse-text文本。若需要自定义按钮样式或文案例如带图标的按钮可使用action插槽插槽作用域暴露{ expanded: boolean }用于区分当前是展开态还是收起态van-text-ellipsis :contenttext template #action{ expanded } {{ expanded ? Collapse : Expand }} /template /van-text-ellipsisexport 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 | string1content展示的文本内容string-expand-text展开操作文案string-collapse-text收起操作文案string-dotsv4.2.0省略号文本内容string...positionv4.6.2省略位置可选startmiddlestringend源码中这些属性的默认值定义在 TextEllipsis.tsxexport 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.tsxTSX 测试中即通过(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 refTextEllipsisInstance(); textEllipsisRef.value?.toggle();类型定义位于 types.tsTextEllipsisInstance由ComponentPublicInstanceTextEllipsisProps, 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.tsx1. 克隆容器进行无痕测量组件并不直接修改真实 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负责把lineHeight等px字符串解析为数字。当maxHeight container.offsetHeight时判定内容超行执行省略计算并渲染操作区否则直接展示完整文本、不渲染操作区。3. 二分查找精确截断点尾部省略positionend使用二分逼近calcEllipse中的tail函数不断尝试「保留前 middle 个字符 省略号」若高度仍超过maxHeight则向左收缩否则向右扩张最终收敛到满足高度约束的最大保留长度保证省略号后不会出现被截断的半行字符。头部省略positionstart逻辑对称保留的是文本尾部。4. 中部省略的双侧逼近中部省略positionmiddle由middleTail函数实现以文本中点为中心对左半部分与右半部分同时做二分收缩左侧收缩用floor、右侧用ceil直到拼接后的「左段 省略号 右段」高度恰好满足约束从而最大化保留开头与结尾的有效信息。5. 响应式重算与 KeepAlive 适配组件对windowWidth来自 utils/dom.ts 的useWindowSize以及content、rows、position的变化做了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),仅供参考