news 2026/9/12 19:13:11

Vant Collapse 折叠面板组件完全指南:从基础用法到源码级原理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vant Collapse 折叠面板组件完全指南:从基础用法到源码级原理

Vant Collapse 折叠面板组件完全指南:从基础用法到源码级原理

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

Vant 的 Collapse 折叠面板用于将一组内容收纳进多个可折叠面板,点击面板标题即可展开或收起内容,是移动端"手风琴"交互(如常见问题、分组设置、筛选条件)的标准实现。本文以 Vant 官方文档为主体,结合仓库内组件源码(Collapse.tsx、CollapseItem.tsx)与测试用例,系统讲解 Collapse 的安装注册、全部 Props/Events/Methods/Slots、toggleAll 实例方法、主题定制变量,并深入剖析父子组件协调、展开动画与懒渲染等底层实现,帮助你在业务中快速落地并理解其工作机制。

安装与组件注册

Collapse 由两个组件组成:Collapse(容器)与CollapseItem(面板项),二者需同时注册。可通过app.use进行全局注册:

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

除全局注册外,Vant 还支持按需引入、unplugin-vue-components自动注册等更多方式,可参考文档 advanced-usage 中的组件注册章节。从源码结构看,collapse/index.ts 与 collapse-item/index.ts 通过withInstall包装组件,并声明了VanCollapse/VanCollapseItem的全局组件类型,注册后可直接在模板中使用<van-collapse><van-collapse-item>标签。

基础用法:用 v-model 控制展开状态

通过v-model绑定当前展开面板的name值。默认(非手风琴)模式下,v-model是一个数组,包含所有已展开面板的 name。

<van-collapse v-model="activeNames"> <van-collapse-item title="Title1" name="1"> The code is written for people to see and can be run on a machine. </van-collapse-item> <van-collapse-item title="Title2" name="2"> Technology is nothing more than the common soul of those who develop it. </van-collapse-item> <van-collapse-item title="Title3" name="3"> The frequency of people swearing during code reading is the only measure of code quality. </van-collapse-item> </van-collapse>
import { ref } from 'vue'; export default { setup() { const activeNames = ref(['1']); return { activeNames }; }, };

name用于唯一标识面板,可传numberstring;当不传name时,默认取面板在当前 Collapse 中的索引(index),这一点在 CollapseItem.tsx 中通过props.name ?? index.value计算得出,demo 源码(demo/index.vue)也展示了ref([0])这种按索引控制的写法。

手风琴模式

开启accordion后,同一时间只允许展开一个面板。

<van-collapse v-model="activeName" accordion> <van-collapse-item title="Title1" name="1"> The code is written for people to see and can be run on a machine. </van-collapse-item> <van-collapse-item title="Title2" name="2"> Technology is nothing more than the common soul of those who develop it. </van-collapse-item> <van-collapse-item title="Title3" name="3"> The frequency of people swearing during code reading is the only measure of code quality. </van-collapse-item> </van-collapse>
import { ref } from 'vue'; export default { setup() { const activeName = ref('1'); return { activeName }; }, };

手风琴模式下v-model绑定的是单个number | string值,而不是数组。源码 Collapse.tsx 中的validateModelValue会进行校验:手风琴模式下v-model为数组、或非手风琴模式下不是数组时,都会在开发环境输出[Vant] Collapse前缀的错误提示。面板切换逻辑位于toggle方法(Collapse.tsx):

  • 手风琴模式:点击已展开的面板会收起(name === modelValue时置为''),点击其他面板则直接切换为当前 name;
  • 非手风琴模式:展开时向数组追加 name,收起时从数组过滤掉该 name,然后统一触发changeupdate:modelValue事件。

测试 index.spec.tsx 验证了手风琴模式下连续点击的切换与收拢行为。

禁用面板

CollapseItem设置disabled后,该面板不可点击展开/收起,标题会呈现禁用态样式。

<van-collapse v-model="activeNames"> <van-collapse-item title="Title1" name="1"> The code is written for people to see and can be run on a machine. </van-collapse-item> <van-collapse-item title="Title2" name="2" disabled> Technology is nothing more than the common soul of those who develop it. </van-collapse-item> <van-collapse-item title="Title3" name="3" disabled> The frequency of people swearing during code reading is the only measure of code quality. </van-collapse-item> </van-collapse>

disabled外,组件还提供readonly(只读)属性。二者在 CollapseItem.tsx 的onClickTitle中都被排除在点击响应之外;区别在于:readonly会额外把标题的isLink置为false并移除clickable样式(CollapseItem.tsx),即只读面板不显示可点击的箭头提示。测试 index.spec.tsx 专门验证了 readonly 面板点击后active不变、且标题不含van-cell--clickable类名。

自定义标题内容

CollapseItem内部标题基于 Vant 的Cell单元格组件实现(CollapseItem.tsx),因此可以使用title插槽完全自定义标题,也可以直接通过titlevaluelabelicon等属性快速组合标题区内容。

<van-collapse v-model="activeNames"> <van-collapse-item name="1"> <template #title> <div>Title1 <van-icon name="question-o" /></div> </template> The code is written for people to see and can be run on a machine. </van-collapse-item> <van-collapse-item title="Title2" name="2" icon="shop-o"> Technology is nothing more than the common soul of those who develop it. </van-collapse-item> </van-collapse>
import { ref } from 'vue'; export default { setup() { const activeNames = ref(['1']); return { activeNames }; }, };

CollapseItem 支持 6 个插槽:default(内容)、title(标题)、value(右侧文字)、label(标题下方描述)、icon(左侧图标)、right-icon(右侧箭头图标)。源码中通过CELL_SLOTS常量(CollapseItem.tsx)将插槽透传给内部Cell,测试 index.spec.tsx 对全部五个 Cell 插槽的渲染进行了快照验证。

全部展开 / 全部切换:toggleAll 方法

通过组件 ref 调用toggleAll实例方法,可以批量操作所有面板的展开状态。注意:toggleAll在手风琴模式下不可用

<van-collapse v-model="activeNames" ref="collapse"> <van-collapse-item title="Title1" name="1"> The code is written for people to see and can be run on a machine. </van-collapse-item> <van-collapse-item title="Title2" name="2"> Technology is nothing more than the common soul of those who develop it. </van-collapse-item> <van-collapse-item title="Title3" name="3"> The frequency of people swearing during code reading is the only measure of code quality. </van-collapse-item> </van-collapse> <van-button type="primary" @click="openAll">Open All</van-button> <van-button type="primary" @click="toggleAll">Toggle All</van-button>
import { ref } from 'vue'; export default { setup() { const activeNames = ref(['1']); const collapse = ref(null); const openAll = () => { collapse.value.toggleAll(true); }; const toggleAll = () => { collapse.value.toggleAll(); }; return { activeNames, openAll, toggleAll, collapse, }; }, };

toggleAll支持布尔值与对象两种参数形式(TypeScript 类型为CollapseToggleAllOptions,定义见 Collapse.tsx):

import { ref } from 'vue'; import type { CollapseInstance } from 'vant'; const collapseRef = ref<CollapseInstance>(); // 全部切换(展开的收起,收起的展开) collapseRef.value?.toggleAll(); // 全部展开 collapseRef.value?.toggleAll(true); // 全部收起 collapseRef.value?.toggleAll(false); // 全部切换,跳过禁用面板 collapseRef.value?.toggleAll({ skipDisabled: true, }); // 全部展开,跳过禁用面板 collapseRef.value?.toggleAll({ expanded: true, skipDisabled: true, });

toggleAll的底层实现在 Collapse.tsx:首先判断props.accordion,手风琴模式下直接return;随后把布尔参数归一化为{ expanded }对象,结合skipDisabled过滤出目标面板集合(禁用且跳过时保持其原有状态),最后汇总所有目标面板的name一次性更新 v-model。

此外,单个面板项也暴露了toggle实例方法(见下文 Types 小节),通过CollapseItemInstance可单独切换某个面板。

API 参考

Collapse Props

属性说明类型默认值
v-model当前展开面板的 name手风琴模式:number | string
非手风琴模式:(number | string)[]
-
accordion是否开启手风琴模式booleanfalse
border是否显示外边框booleantrue

源码中collapseProps的定义(Collapse.tsx)显示border使用truthProp(默认true)、accordion为布尔开关、modelValue接受String | Number | Array。当bordertrue时容器会挂载van-hairline--top-bottom细边框类名,测试 index.spec.tsx 验证了border: false时该边框类名不会出现。

Collapse Events

事件名说明回调参数
change切换面板时触发activeNames: string | number | Array<string | number>

changeupdate:modelValueupdateName中一并触发(Collapse.tsx),前者用于业务监听,后者用于支持v-model双向绑定。

CollapseItem Props

属性说明类型默认值
name面板唯一标识number | stringindex
icon左侧图标string-
size标题大小,可设为largestring-
title标题number | string-
value右侧文字number | string-
label标题下方的描述文字string-
border是否显示内边框booleantrue
disabled是否禁用面板booleanfalse
readonly是否只读(不显示箭头、不可点击)booleanfalse
is-link是否显示右侧链接箭头booleantrue
lazy-render是否在首次展开时才渲染内容booleantrue
title-class标题类名string-
value-class右侧文字类名string-
label-class描述文字类名string-

name的类型为numericPropdisabled/readonly为布尔开关,isLinklazyRender均使用truthProp(默认true);其余titlevaluelabeliconsize及三个 class 属性来自cellSharedProps,与Cell组件共享(CollapseItem.tsx)。

Collapse Methods

通过 ref 获取 Collapse 实例并调用实例方法。

方法名说明参数返回值
toggleAll切换所有面板的展开状态options?: boolean | object-

CollapseItem Methods

方法名说明参数返回值
toggle切换面板展开状态expanded: boolean-

CollapseItemtoggle通过useExpose暴露(CollapseItem.tsx),默认在传入值与当前状态之间取反,最终调用父组件通过依赖注入下发的parent.toggle(name, newValue);测试 index.spec.tsx 分别验证了普通模式与手风琴模式下调用toggle()/toggle(false)对 active 值的影响。

Types

组件导出了以下 TypeScript 类型:

import type { CollapseProps, CollapseItemProps, CollapseItemInstance, CollapseToggleAllOptions, } from 'vant';

CollapseItemInstance为组件实例类型,可用于调用单项toggle方法:

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

这些类型分别定义于 Collapse.tsx(CollapseToggleAllOptionsCollapsePropsCollapseInstance)与 collapse-item/types.ts(CollapseItemExposeCollapseItemInstance),并由各自 index.ts 统一导出。

CollapseItem Slots

插槽名说明
default面板内容
title自定义标题
value自定义右侧文字
label自定义标题下方描述
icon自定义左侧图标
right-icon自定义右侧箭头图标

主题定制:CSS Variables

Collapse 组件对外暴露以下 CSS 变量,可通过 ConfigProvider 组件 或直接在:root上覆盖,实现全局或局部主题定制。这些变量的默认值定义在 collapse-item/index.less 中:

变量名默认值说明
--van-collapse-item-durationvar(--van-duration-base)展开/收起动画时长
--van-collapse-item-content-paddingvar(--van-padding-sm) var(--van-padding-md)内容区内边距
--van-collapse-item-content-font-sizevar(--van-font-size-md)内容区字号
--van-collapse-item-content-line-height1.5内容区行高
--van-collapse-item-content-text-colorvar(--van-text-color-2)内容区文字颜色
--van-collapse-item-content-backgroundvar(--van-background-2)内容区背景色
--van-collapse-item-title-disabled-colorvar(--van-text-color-3)禁用标题文字颜色

除上述 7 个可直接覆盖的变量外,types.ts 还导出了CollapseItemThemeVars类型,便于在 TS 项目中获得主题变量名的类型提示。展开/收起动画基于height过渡实现:.van-collapse-item__wrapper设置overflow: hiddentransition: height var(--van-collapse-item-duration) ease-in-out,标题右侧箭头在展开态通过rotate(-90deg)旋转(collapse-item/index.less)。

源码级原理:父子协调、动画与懒渲染

Collapse 采用典型的"父组件通过依赖注入协调子组件"架构,理解这一机制有助于排查"面板状态不同步"类问题。

父子通信Collapse在 Collapse.tsx 中定义注入 keyCOLLAPSE_KEY,通过@vant/useuseChildren收集所有CollapseItem子组件,并linkChildren下发toggleisExpanded两个方法(Collapse.tsx);CollapseItem侧用useParent(COLLAPSE_KEY)获取父组件上下文,若脱离Collapse单独使用,开发环境下会输出<CollapseItem> must be a child component of <Collapse>的错误提示(CollapseItem.tsx)。每个面板的展开状态并不自持,而是实时通过parent.isExpanded(name)从父级 v-model 推导(CollapseItem.tsx),因此 v-model 是状态的唯一数据源。

展开动画CollapseItem监听expanded变化后,先测量内容区offsetHeight,再利用raf/nextTickdoubleRaf分帧设置 wrapper 的height0到实际高度(展开)或反向过渡(收起),动画结束后在onTransitionEnd中清理高度并隐藏内容(CollapseItem.tsx)。注释指出:展开用nextTick是为了避免 Safari 中打开时的闪烁,收起用raf是为了规避user-select: none场景下关闭动画失效的问题。

懒渲染lazyRender默认开启,内容通过 use-lazy-render 包裹,只有面板首次展开(show.value为真)时才渲染默认插槽内容,未展开的面板不生成内容 DOM;测试 index.spec.tsx 验证了点击标题前.foo元素不存在、展开后才出现的完整流程。该特性在面板内容较重时能显著降低首屏渲染成本。

小结

Collapse 折叠面板覆盖了移动端最常见的"折叠-展开"交互场景:普通多面板模式与手风琴模式通过accordion一键切换,disabled/readonly满足权限控制需求,6 个插槽 + 继承自 Cell 的属性让标题区可以自由定制,toggleAll与单项toggle实例方法支持程序化批量操作,7 个 CSS 变量则让主题定制无需修改组件源码。结合本文对COLLAPSE_KEY依赖注入、高度过渡动画与懒渲染的实现分析,你不仅能在项目中熟练使用,也能在遇到交互异常时快速定位到 Collapse.tsx 与 CollapseItem.tsx 中的对应逻辑。

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

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 19:12:44

OpenClaw与白山智算平台对接实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 19:12:40

TDengine时序数据库在工业AI场景的应用实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 19:11:46

大模型业务可观测体系建设:我们该重点监控哪些指标

很多 AI 项目&#xff0c;本地 Demo 测试效果出色&#xff0c;上线生产环境之后故障频发&#xff0c;但是研发很难定位问题根源。缺少面向大模型场景的可观测体系&#xff0c;是非常普遍的工程短板。传统后端服务监控&#xff0c;重点关注 CPU、内存、QPS&#xff0c;这套指标无…

作者头像 李华
网站建设 2026/9/12 19:07:32

正则表达式到自动机:Python实现NFA确定化与DFA最小化

简介&#xff1a;基于Python实现的编译原理课程设计资源包&#xff0c;围绕正则表达式转NFA、NFA确定化及DFA最小化三个核心环节&#xff0c;提供完整可运行的Python源码与配套说明文档&#xff0c;适合计算机专业学生学习编译原理或完成形式语言作业时参考。压缩包共9个文件&a…

作者头像 李华
网站建设 2026/9/12 19:05:59

Spring Boot + WebSocket 即时聊天系统:从握手到断线重连全解析

简介&#xff1a;基于Spring Boot与WebSocket并结合JavaScript实现的即时聊天系统&#xff0c;面向需要了解Web实时通信机制的初中级开发者。资源压缩包内含99个文件&#xff0c;总大小10.7MB&#xff0c;其中包含25个Java源文件、13个JS文件、9个CSS文件及4个HTML页面&#xf…

作者头像 李华
网站建设 2026/9/12 19:02:52

Spring Boot 将配置绑定到第三方对象详解

Spring Boot 将配置绑定到第三方对象详解 在 Spring Boot 中&#xff0c;配置绑定通常用于将配置文件中的属性映射到我们自己的 Java 类&#xff08;Bean&#xff09;上&#xff0c;这可以通过 ConfigurationProperties 轻松实现。然而&#xff0c;在实际开发中&#xff0c;我们…

作者头像 李华