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:openbooleanundefined受控展开状态。
Collapsible defaultOpenbooleanfalse非受控初始展开状态。
Collapsible disabledbooleanfalse禁用交互。
CollapsibleTrigger as / asChildstring | Component / boolean'button' / false触发器的元素组合能力。
CollapsibleContent classHTMLAttributes["class"]undefined合并到内容区的调用方类。