Collapsible 展开收起
用于展开收起场景的 MoriUI 组件。
导入
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from 'moriui'
示例
概览
展开或收起订单详情。
订单 #4189
状态已发货
<script setup lang="ts">
import { ref } from 'vue'
import { ChevronsUpDown } from '@lucide/vue'
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger } from 'moriui'
const isOpen = ref(false)
</script>
<template>
<Collapsible
v-model:open="isOpen"
class="flex w-[350px] flex-col gap-2"
>
<div class="flex items-center justify-between gap-4 px-4">
<h4 class="text-sm font-semibold">
订单 #4189
</h4>
<CollapsibleTrigger as-child>
<Button variant="ghost" size="icon" class="size-8">
<ChevronsUpDown />
<span class="sr-only">切换详情</span>
</Button>
</CollapsibleTrigger>
</div>
<div class="flex items-center justify-between rounded-md border px-4 py-2 text-sm">
<span class="text-muted-foreground">状态</span>
<span class="font-medium">已发货</span>
</div>
<CollapsibleContent class="flex flex-col gap-2">
<div class="rounded-md border px-4 py-2 text-sm">
<p class="font-medium">
收货地址
</p>
<p class="text-muted-foreground">
北京市朝阳区 100 号
</p>
</div>
<div class="rounded-md border px-4 py-2 text-sm">
<p class="font-medium">
商品
</p>
<p class="text-muted-foreground">
2x 降噪耳机
</p>
</div>
</CollapsibleContent>
</Collapsible>
</template>
基础
最小化的展开收起。
<script setup lang="ts">
import { shallowRef } from 'vue'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from 'moriui'
const isOpen = shallowRef(false)
</script>
<template>
<Collapsible v-model:open="isOpen" class="w-full max-w-sm">
<CollapsibleTrigger class="flex w-full items-center justify-between rounded-md border px-4 py-2 text-sm font-medium hover:bg-muted/50">
<span>了解更多</span>
<span aria-hidden="true" class="text-muted-foreground">{{ isOpen ? '−' : '+' }}</span>
</CollapsibleTrigger>
<CollapsibleContent class="mt-2 rounded-md border px-4 py-3 text-sm text-muted-foreground">
Collapsible 是一个可折叠的内容容器,用于隐藏和显示额外信息。点击触发按钮可切换内容区域的可见性。
</CollapsibleContent>
</Collapsible>
</template>
文件目录
嵌套 Collapsible 展示目录结构。
project
index.html
package.json
<script setup lang="ts">
import { shallowRef } from 'vue'
import { ChevronRight, File, Folder } from '@lucide/vue'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from 'moriui'
const srcOpen = shallowRef(true)
const componentsOpen = shallowRef(false)
const utilsOpen = shallowRef(false)
</script>
<template>
<div class="w-full max-w-sm rounded-md border p-3 text-sm font-mono">
<div class="flex items-center gap-2 px-2 py-1 text-muted-foreground">
<Folder class="size-4 text-blue-500" />
<span class="font-medium text-foreground">project</span>
</div>
<div class="ml-4 border-l pl-3">
<Collapsible v-model:open="srcOpen">
<CollapsibleTrigger class="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-muted/50">
<ChevronRight class="size-3 transition-transform" :class="srcOpen && 'rotate-90'" />
<Folder class="size-4 text-yellow-500" />
<span>src</span>
</CollapsibleTrigger>
<CollapsibleContent class="ml-4 border-l pl-3">
<Collapsible v-model:open="componentsOpen">
<CollapsibleTrigger class="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-muted/50">
<ChevronRight class="size-3 transition-transform" :class="componentsOpen && 'rotate-90'" />
<Folder class="size-4 text-yellow-500" />
<span>components</span>
</CollapsibleTrigger>
<CollapsibleContent class="ml-4 border-l pl-3">
<div class="flex items-center gap-2 rounded px-2 py-1 text-muted-foreground">
<File class="size-4" />
<span>Button.vue</span>
</div>
<div class="flex items-center gap-2 rounded px-2 py-1 text-muted-foreground">
<File class="size-4" />
<span>Card.vue</span>
</div>
<div class="flex items-center gap-2 rounded px-2 py-1 text-muted-foreground">
<File class="size-4" />
<span>Modal.vue</span>
</div>
</CollapsibleContent>
</Collapsible>
<Collapsible v-model:open="utilsOpen">
<CollapsibleTrigger class="flex w-full items-center gap-2 rounded px-2 py-1 hover:bg-muted/50">
<ChevronRight class="size-3 transition-transform" :class="utilsOpen && 'rotate-90'" />
<Folder class="size-4 text-yellow-500" />
<span>utils</span>
</CollapsibleTrigger>
<CollapsibleContent class="ml-4 border-l pl-3">
<div class="flex items-center gap-2 rounded px-2 py-1 text-muted-foreground">
<File class="size-4" />
<span>format.ts</span>
</div>
<div class="flex items-center gap-2 rounded px-2 py-1 text-muted-foreground">
<File class="size-4" />
<span>validate.ts</span>
</div>
</CollapsibleContent>
</Collapsible>
</CollapsibleContent>
</Collapsible>
<div class="flex items-center gap-2 rounded px-2 py-1 text-muted-foreground">
<File class="size-4" />
<span>index.html</span>
</div>
<div class="flex items-center gap-2 rounded px-2 py-1 text-muted-foreground">
<File class="size-4" />
<span>package.json</span>
</div>
</div>
</div>
</template>
设置面板
分组设置项展开。
设置
语言简体中文
主题跟随系统
时区UTC+8
<script setup lang="ts">
import { shallowRef } from 'vue'
import {
Bell,
ChevronDown,
Eye,
Settings,
Shield,
User
} from '@lucide/vue'
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from 'moriui'
const generalOpen = shallowRef(true)
const notifyOpen = shallowRef(false)
const privacyOpen = shallowRef(false)
</script>
<template>
<div class="w-full max-w-sm rounded-md border">
<div class="border-b px-4 py-3 text-sm font-semibold">
<div class="flex items-center gap-2">
<Settings class="size-4" />
<span>设置</span>
</div>
</div>
<div class="divide-y">
<Collapsible v-model:open="generalOpen">
<CollapsibleTrigger class="flex w-full items-center gap-3 px-4 py-3 text-sm font-medium hover:bg-muted/50">
<User class="size-4 text-muted-foreground" />
<span class="flex-1 text-left">通用</span>
<ChevronDown class="size-4 text-muted-foreground transition-transform" :class="generalOpen && 'rotate-180'" />
</CollapsibleTrigger>
<CollapsibleContent class="px-4 pb-3 text-sm text-muted-foreground">
<div class="flex items-center justify-between rounded-md px-2 py-1.5 hover:bg-muted/30">
<span>语言</span>
<span class="text-xs">简体中文</span>
</div>
<div class="flex items-center justify-between rounded-md px-2 py-1.5 hover:bg-muted/30">
<span>主题</span>
<span class="text-xs">跟随系统</span>
</div>
<div class="flex items-center justify-between rounded-md px-2 py-1.5 hover:bg-muted/30">
<span>时区</span>
<span class="text-xs">UTC+8</span>
</div>
</CollapsibleContent>
</Collapsible>
<Collapsible v-model:open="notifyOpen">
<CollapsibleTrigger class="flex w-full items-center gap-3 px-4 py-3 text-sm font-medium hover:bg-muted/50">
<Bell class="size-4 text-muted-foreground" />
<span class="flex-1 text-left">通知</span>
<ChevronDown class="size-4 text-muted-foreground transition-transform" :class="notifyOpen && 'rotate-180'" />
</CollapsibleTrigger>
<CollapsibleContent class="px-4 pb-3 text-sm text-muted-foreground">
<div class="flex items-center justify-between rounded-md px-2 py-1.5 hover:bg-muted/30">
<span>推送通知</span>
<span class="text-xs">已开启</span>
</div>
<div class="flex items-center justify-between rounded-md px-2 py-1.5 hover:bg-muted/30">
<span>邮件提醒</span>
<span class="text-xs">已关闭</span>
</div>
</CollapsibleContent>
</Collapsible>
<Collapsible v-model:open="privacyOpen">
<CollapsibleTrigger class="flex w-full items-center gap-3 px-4 py-3 text-sm font-medium hover:bg-muted/50">
<Shield class="size-4 text-muted-foreground" />
<span class="flex-1 text-left">隐私</span>
<ChevronDown class="size-4 text-muted-foreground transition-transform" :class="privacyOpen && 'rotate-180'" />
</CollapsibleTrigger>
<CollapsibleContent class="px-4 pb-3 text-sm text-muted-foreground">
<div class="flex items-center justify-between rounded-md px-2 py-1.5 hover:bg-muted/30">
<span>在线状态</span>
<span class="text-xs">所有人可见</span>
</div>
<div class="flex items-center justify-between rounded-md px-2 py-1.5 hover:bg-muted/30">
<Eye class="size-3.5" />
<span>活动记录</span>
<span class="text-xs">仅自己</span>
</div>
</CollapsibleContent>
</Collapsible>
</div>
</div>
</template>
RTL
从右到左的折叠面板。
الطلب #4189
الحالةتم الشحن
<script setup lang="ts">
import { shallowRef } from 'vue'
import { ChevronsUpDown } from '@lucide/vue'
import { Button, Collapsible, CollapsibleContent, CollapsibleTrigger, DirectionProvider } from 'moriui'
const isOpen = shallowRef(false)
</script>
<template>
<DirectionProvider dir="rtl">
<Collapsible
v-model:open="isOpen"
class="flex w-[350px] flex-col gap-2"
>
<div class="flex items-center justify-between gap-4 px-4">
<h4 class="text-sm font-semibold">
الطلب #4189
</h4>
<CollapsibleTrigger as-child>
<Button variant="ghost" size="icon" class="size-8">
<ChevronsUpDown />
<span class="sr-only">تبديل التفاصيل</span>
</Button>
</CollapsibleTrigger>
</div>
<div class="flex items-center justify-between rounded-md border px-4 py-2 text-sm">
<span class="text-muted-foreground">الحالة</span>
<span class="font-medium">تم الشحن</span>
</div>
<CollapsibleContent class="flex flex-col gap-2">
<div class="rounded-md border px-4 py-2 text-sm">
<p class="font-medium">
عنوان الشحن
</p>
<p class="text-muted-foreground">
شارع الاستقلال، الرياض
</p>
</div>
<div class="rounded-md border px-4 py-2 text-sm">
<p class="font-medium">
المنتجات
</p>
<p class="text-muted-foreground">
2x سماعات رأس
</p>
</div>
</CollapsibleContent>
</Collapsible>
</DirectionProvider>
</template>
使用说明
组合方式
Collapsible 由 Trigger 和 Content 组成,通过 v-model:open 控制展开状态。
RTL
Collapsible 内容沿外围 dir 排列。
变体
Collapsible 没有视觉变体;open/closed 状态由 Reka UI 的 data-state 驱动。
可访问性
Collapsible 复用 Reka UI Collapsible 的 button 和 region 角色、aria-expanded、aria-controls 和隐藏内容管理。Trigger 应提供清晰可理解的控制标签。
API 参考
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Collapsible v-model:open | boolean | undefined | 受控展开状态。 |
Collapsible defaultOpen | boolean | false | 非受控初始展开状态。 |
Collapsible disabled | boolean | false | 禁用交互。 |
CollapsibleTrigger as / asChild | string | Component / boolean | 'button' / false | 触发器的元素组合能力。 |
CollapsibleContent class | HTMLAttributes["class"] | undefined | 合并到内容区的调用方类。 |