Skip to content

Accordion 手风琴 ​

一组纵向排列、各自可展开的区块。适合 FAQ、设置分组这类「标题一眼扫完、需要时再展开细节」的内容。 只有一块内容要折叠时用 Collapsible 折叠面板。

基础用法

每一项的标题放进 trigger 插槽、内容放默认插槽。默认 single:同一时间最多展开一项;collapsible 让已展开的那项能再点收起。

<pt-accordion value="refund" collapsible>
  <pt-accordion-item value="refund">
    <span slot="trigger">能退款吗?</span>
    购买 7 天内可无理由退款,原路退回。
  </pt-accordion-item>
  <pt-accordion-item value="payment">
    <span slot="trigger">支持哪些付款方式?</span>
    信用卡、支付宝与银行转账。
  </pt-accordion-item>
  <pt-accordion-item value="invoice">
    <span slot="trigger">怎么开发票?</span>
    在「账单」页选择对应订单,填写抬头后即时开具。
  </pt-accordion-item>
</pt-accordion>
多项展开与禁用

type="multiple" 时各项独立展开,value 是字符串数组(HTML 里写成逗号分隔)。禁用的项点不开,方向键也跳过它。

<pt-accordion type="multiple" value="general,privacy">
  <pt-accordion-item value="general">
    <span slot="trigger">通用</span>
    语言、时区与默认首页。
  </pt-accordion-item>
  <pt-accordion-item value="privacy">
    <span slot="trigger">隐私</span>
    数据保留期限与访客 IP 匿名化。
  </pt-accordion-item>
  <pt-accordion-item value="billing" disabled>
    <span slot="trigger">计费(仅组织所有者可改)</span>
    套餐与付款方式。
  </pt-accordion-item>
</pt-accordion>

结构 ​

pt-accordion 里直接放若干 pt-accordion-item;每一项的标题放进 trigger 插槽,内容放默认插槽。 项必须是 pt-accordion 的直接子元素 —— 手风琴只认自己的直接子项,所以可以放心嵌套,内外层互不串。

每一项都写上 value,展开态靠它对应。没写的项也能点开,但它的键是内部分配的,没法事先写进 value 受控。

受控值 ​

受控属性是 value,事件是 ptChange:

typevalue 的形状全部收起时
single(默认)字符串:展开那一项的 value''
multiple字符串数组:展开的各项的 value[]
  • Vue:<PtAccordion v-model="open">
  • Angular:<pt-accordion [(ngModel)]="open">,standalone 组件要在 imports 里加上 TextValueAccessor
  • React:<PtAccordion value={open} onPtChange={e => setOpen(e.detail)}>

数组只能用 JS / 框架绑定赋值;在 HTML 里写 multiple 的初始值时用逗号分隔:value="general,privacy" (各段去掉首尾空白)。因此 multiple 下项的 value 本身不要含逗号。

ptChange 只在用户点击标题切换时发;外部直接改 value 只改状态,不发事件。 multiple 下组件写回的总是一个新数组,Vue / React 的浅比较能感知变化。

ptChange 不冒泡

手风琴会嵌套,而三个框架的双向绑定都挂在宿主上 —— 冒泡的话展开内层的项会连带改写外层绑定。 要在外层容器上统一监听,用捕获阶段:el.addEventListener('ptChange', fn, true)。

可收起 ​

single 下默认总有一项开着:再点已展开的那项不会收起它。加 collapsible 后可以,收起后 value 为空串。 multiple 下各项本来就能各自收起,collapsible 无意义。

禁用 ​

项上的 disabled 只禁用那一项;pt-accordion 上的 disabled 禁用全部项。被禁用的标题不可点、不可聚焦, 方向键跳过它。禁用只拦用户操作 —— 外部改 value 照样能展开 / 收起。

键盘与无障碍 ​

按 WAI-ARIA Accordion 模式:

  • 每一项的标题都是一个原生按钮,全部在 Tab 序列里;Enter / Space 切换。
  • 焦点在某个标题上时,↑ ↓ 在各项标题之间移动(到头回绕),Home / End 跳到第一项 / 最后一项。 焦点在内容里(比如输入框)时方向键不归手风琴管。
  • 标题外面包着 role="heading",层级用项上的 heading-level 设(默认 3),按它在页面标题结构里的实际位置给。
  • 按钮带 aria-expanded、aria-controls;内容区是 role="region",以标题为名。

收起时内容区 inert 且不可见:Tab 不会走进看不见的内容,读屏也不会读到它。 展开 / 收起的高度过渡与 Collapsible 相同,系统开了「减少动态效果」时直接切换。

API ​

属性

属性Attribute类型默认值说明
collapsiblecollapsiblebooleanfalse`single` 下再点已展开的那一项能否把它收起(收起后 `value` 为空串)。默认不能 —— 总有一项开着。`multiple` 下无意义
disableddisabledbooleanfalse禁用整个手风琴:全部标题不可点、不可聚焦。不影响通过 `value` 控制展开态
typetype"multiple" | "single"'single'展开方式: - `single`:同一时间最多展开一项,点开另一项时原来那项收起; - `multiple`:各项独立展开。
valuevaluestring | string[]''展开着的项的 `value`。 - `single`:字符串,空串表示全部收起; - `multiple`:字符串数组。数组只能用 JS / 框架绑定赋值;写成 HTML attribute 时用**逗号分隔** (`value="a,c"`,各段去掉首尾空白),因此 multiple 下项的 `value` 本身不要含逗号。 用户点击标题时组件自己改写它(multiple 下总是写回一个新数组)并发 `ptChange`;外部直接赋值不发事件。

事件

事件detail 类型说明
ptChangestring | string[]用户点击标题切换展开态后触发,detail 是切换后的 `value`(`single` 为字符串、`multiple` 为字符串数组)。 **不冒泡**(与其它组件的默认相反):手风琴会嵌套,而三个框架的双向绑定都挂在宿主上 —— Vue 的 v-model 只按 tagName 过滤冒泡事件,内外层同是 PT-ACCORDION 拦不住。冒泡的话展开内层的项 会连带改写外层绑定。要在外层容器上统一监听,用捕获阶段(`addEventListener('ptChange', fn, true)`)。

方法

方法说明
refresh() => Promise<void>重新按 `value` 同步各项的展开态。子项增删、改 value 时组件自己会调,一般不需要手动调用

插槽

名称说明
(默认)若干 `pt-accordion-item`

pt-accordion-item ​

属性

属性Attribute类型默认值说明
disableddisabledbooleanfalse禁用这一项:标题按钮不可点、不可聚焦,方向键跳过它。父 `pt-accordion` 的 `disabled` 也会禁用全部项
headingLevelheading-levelnumber3标题的层级(`aria-level`),按它在页面标题结构里的位置给,1–6。默认 3
openopenbooleanfalse是否展开。由父 `pt-accordion` 按它的 `value` 回写,只读;样式可用 `pt-accordion-item[open]`
valuevaluestring | undefined—这一项的值,父元素 `value` 里出现它就展开。同一个手风琴里要唯一。 不给时父元素会给它分配一个内部键(照样能点开),但那个键没法事先写进 `value`,也就没法受控 —— 建议总是写上

插槽

名称说明
(默认)展开后显示的内容
trigger标题内容(文字,或文字加图标)。整行都是按钮,不要在里面放别的可交互元素

可定制的内部元素(::part())

part说明
body内容的内边距层
content内容区(做高度过渡的那一层,role="region")
heading标题行(role="heading")
icon标题尾部的展开指示箭头
trigger标题按钮

Apache-2.0 协议开源