naive-ui CollapseTransition 折叠渐变组件:从 Props 到源码实现的全方位指南

发布时间:2026/9/21 15:51:21
naive-ui CollapseTransition 折叠渐变组件:从 Props 到源码实现的全方位指南 naive-ui CollapseTransition 折叠渐变组件从 Props 到源码实现的全方位指南【免费下载链接】naive-uiA Vue 3 Component Library. Fairly Complete. Theme Customizable. Uses TypeScript. Fast.项目地址: https://gitcode.com/gh_mirrors/na/naive-ui导读CollapseTransition折叠渐变是 naive-ui 提供的一个无封装的高度可复用过渡组件它只负责一件事——在内容显示与隐藏之间播放平滑的高度折叠 透明度渐变动画而把按钮、标题栏等外层交互完全交由开发者自由组织。无论是实现手风琴菜单、折叠面板还是展开更多区块这个组件都能以最小的心智负担直接接入。读完本文你将掌握它的全部 Props、Slot 用法、RTL 支持方式并能从源码层面理解其动画原理、v-if/v-show切换策略及主题定制入口。本文基于仓库中 中文文档 与对应 英文文档 展开并结合组件实现源码进行纵深验证。一、组件概览一个没什么封装的折叠过渡官方文档对它的定位非常直白一个没什么封装的 collapse itemA collapse item without any form of encapsulation。这句话包含两层含义它不负责业务逻辑不像NCollapse/NCollapseItem那样管理展开项索引、互斥展开等状态也不渲染任何标题栏、箭头图标它只做纯粹的视觉过渡接受一个show布尔值在切换时自动播放高度与透明度的渐变动画。因此它非常适合被封装进你自己的业务组件中例如自定义的查看更多卡片、FAQ 折叠列表作为动画层使用。其入口文件 index.ts 导出了NCollapseTransition组件与CollapseTransitionProps类型。二、基本用法与首个 Demo在模板中注册后即可使用核心只需要控制show一个属性template n-space vertical n-switch v-model:valueshow template #checked展开/template template #unchecked折叠/template /n-switch n-collapse-transition :showshow 感知度方法论组合拳引爆点点线面精细化差异化…… /n-collapse-transition /n-space /template script langts setup import { ref } from vue const show ref(true) /script上述代码即仓库中 基本用法 Demo 的完整内容。要点show为true时内容显示为false时内容折叠并淡出内容可以是任意文本或子组件通过 default slot 传入切换开关即可看到 0.3 秒的高度折叠 透明度渐变效果具体时长见下文样式分析。三、API 详解3.1 CollapseTransition Props名称类型默认值说明版本appearbooleanfalse是否在首次挂载时播放动画—display-directiveif \| showif内置元素渲染使用的指令if使用v-ifshow使用v-show2.45.0showbooleantrue是否展示内容—各 Props 的语义与源码对应关系如下。show显示控制组件的核心开关声明于 CollapseTransition.tsx。从源码结构可以推断渲染时组件会先判断是否应该渲染内容再交由内部过渡组件处理动画show: { type: Boolean, default: true }display-directive渲染指令策略2.45.0 新增控制内置元素采用v-if还是v-show渲染默认ifif通过v-if渲染内容在隐藏时会被彻底移除不占用 DOM 节点show通过v-show渲染内容始终存在于 DOM 中仅切换display。从 CollapseTransition.tsx 可以看到一个关键细节show模式只有在mergedShow曾经为真onceTrue之后才会启用即首次渲染前不会直接挂载隐藏内容避免无谓的初始渲染开销const onceTrueRef useFalseUntilTruthy(mergedShowRef) // ... const useVShow displayDirective show onceTrue if (!useVShow !mergedShow) return // ... return useVShow ? withDirectives(contentNode, [[vShow, mergedShow]]) : contentNodeappear首帧动画为true时组件首次挂载也会播放一次展开动画。该值会透传给内部使用的NFadeInExpandTransition见 CollapseTransition.tsx由它把appear绑定到 Vue 的Transition appear上见 FadeInExpandTransition.ts。已废弃的collapsed源码中还存在一个历史遗留属性collapsedCollapseTransition.tsx它被标记为deprecated。值得注意的是实现上存在一个已知反转问题collapsedtrue反而会让内容显示源码注释中明确说明 No mistake, its implemented with error at first, just keep it here即首次实现时写反了为兼容只能保留。在开发环境下只要传入该属性就会触发warnOnce警告提示改用show。新代码请一律使用showwatchEffect(() { if (props.collapsed ! undefined) { warnOnce( collapse-transition, collapsed is deprecated, please use show instead ) } })3.2 CollapseTransition Slots名称参数说明default()渐变的内容Slot 无任何参数渲染进内部包裹的div classn-collapse-transition中。仓库的 组件测试 验证了 default slot 的内容会被正确渲染并保留文本it(should work with default slot, async () { const wrapper mount(NCollapseTransition, { slots: { default: () test } }) expect(wrapper.find(.n-collapse-transition).exists()).toBe(true) expect(wrapper.find(.n-collapse-transition).text()).toBe(test) wrapper.unmount() })四、原理剖析动画是如何实现的4.1 两层结构CollapseTransition → FadeInExpandTransitionNCollapseTransition自身并不直接写动画代码而是复用了 naive-ui 内部的 NFadeInExpandTransition 通用过渡组件同样被 Tree、DataTable 等组件内部使用。从 渲染函数 可以看到调用链render() { return ( NFadeInExpandTransition appear{this.appear} {{ default: () { // 根据 mergedShow / displayDirective 决定是否渲染内容节点 // 渲染 div classn-collapse-transition 样式变量 $slots } }} /NFadeInExpandTransition ) }外层包裹的 div 拥有类名${mergedClsPrefix}-collapse-transition默认前缀下即n-collapse-transition其 CSS 由 index.cssr.ts 定义宽度100%并挂载高度展开过渡样式export default cB(collapse-transition, { width: 100% }, [ fadeInHeightExpandTransition() ])4.2 高度动画的关键技巧max-height 过渡展开/折叠动画的核心在 FadeInExpandTransition.ts 的钩子函数中。由于内容高度不固定直接对height做 CSS 过渡无法获得动画终点组件采用经典的max-height 过渡方案进入时handleEnter先关闭过渡并测量内容实际高度el.offsetHeight将max-height置0强制回流再恢复过渡并把max-height设为目标高度从而从 0 平滑展开到实际高度离开时handleBeforeLeave/handleLeave先把max-height固定为当前实际高度再置0完成折叠结束后handleAfterLeave/handleAfterEnter清空内联的max-height避免残留样式影响布局。同时动画还同步处理了opacity、margin、padding的过渡折叠时可选择是否将 padding 一并折叠为 0完整定义见 fade-in-height-expand.cssr.ts。默认过渡时长duration .3s缓动函数使用cubicBezierEaseInOut进出场 opacity 分别使用 ease-in / ease-out 微调观感并默认overflow: hidden防止动画过程中内容溢出。4.3 主题变量与定制CollapseTransition也是主题系统的一员其 light.ts 定义了一个主题变量bezier即动画使用的贝塞尔曲线取自全局公共变量cubicBezierEaseInOut运行时以 CSS 变量--n-bezier注入到元素上见 CollapseTransition.tsx。如果需要通过NConfigProvider的theme-overrides调整动画曲线可覆盖CollapseTransition主题下的bezier字段暗色主题 dark.ts 与亮色主题共享同一套self定义。五、RTL 支持与调试 Demo折叠过渡还提供了 RTL从右到左排版支持。仓库在 rtl.ts 中导出了collapseTransitionRtl并通过 styles.ts 以unstableCollapseTransitionRtl的名字暴露给用户export { collapseTransitionRtl as unstableCollapseTransitionRtl } from ./collapse-transition/styles其样式定义在 rtl.cssr.ts核心是把内容方向切换为rtl并对齐到右侧export default cB(collapse-transition, [ cM(rtl, direction: rtl; text-align: right; ) ])仓库自带的 RTL 调试 Demo 演示了接入方式——将unstableCollapseTransitionRtl放入数组通过NConfigProvider的rtl属性动态切换script langts setup import { unstableCollapseTransitionRtl } from naive-ui import { ref } from vue const rtlEnabled ref(false) const rtlStyles [unstableCollapseTransitionRtl] const show ref(true) /script template n-config-provider :rtlrtlEnabled ? rtlStyles : undefined n-space vertical n-switch v-model:valueshow template #checkedShow/template template #uncheckedHide/template /n-switch n-collapse-transition :showshow 感知度方法论组合拳引爆点点线面…… /n-collapse-transition /n-space /n-config-provider /template提示unstableCollapseTransitionRtl名称中的unstable前缀表明其 API 未来可能调整属于不稳定但可用的接口接入时留意版本变更日志即可。六、测试与 SSR 保障仓库为该组件提供了两类测试可作为接入时的行为参考CollapseTransition.spec.tsx验证按需引入可用、showfalse时内容节点被移除、default slot 内容正确渲染server.spec.tsx在vitest-environment node下验证 SSR 服务端渲染不会抛错说明该组件可以安全地用于服务端渲染场景。七、实战组合封装一个带标题的折叠面板基于以上知识可以轻松把NCollapseTransition封装成自己的业务组件。示例思路非仓库代码仅供演示template div classmy-panel button classmy-panel__header clickopen !open {{ open ? 收起 : 展开 }}详情 /button n-collapse-transition :showopen div classmy-panel__bodyslot //div /n-collapse-transition /div /template script langts setup import { ref } from vue const open ref(false) /script几个实践建议内容固定宽度内部节点宽度由外层容器决定外层 div 已设置width: 100%不要在内部节点上使用百分比宽度依赖自身以免测量出现误差show而非collapsed不要使用已废弃且语义反的collapsed属性首屏动画若希望页面加载时内容以动画形式出现设置appear为true频繁切换的复杂内容若内容较重、希望避免反复销毁重建可考虑display-directiveshow2.45.0让隐藏仅切换display而保留 DOM。结语CollapseTransition虽小却是理解 naive-ui 动画体系的一个绝佳切片对外是零封装的极简 API对内则复用通用的FadeInExpandTransition与max-height过渡方案并完整接入主题变量与 RTL 体系。阅读源码时建议从 CollapseTransition.tsx 出发依次追踪 FadeInExpandTransition.ts 与 fade-in-height-expand.cssr.ts即可掌握 naive-ui 内部大量组件共用同一套高度过渡的底层机制。【免费下载链接】naive-uiA Vue 3 Component Library. Fairly Complete. Theme Customizable. Uses TypeScript. Fast.项目地址: https://gitcode.com/gh_mirrors/na/naive-ui创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考