Skip to content

Sheet 侧边面板 ​

从视口一侧滑出的模态面板,放筛选条件、详情、次要表单这类「看一眼 / 改一下就回来」的内容。 打断流程、要求明确答复的用 Modal。

基础结构

标题、说明、正文、底部操作各占一个插槽。面板初始是关闭的:把 open 设为 true 或调用 show() 才会从 side 指定的一侧滑出,这里只展示结构。

侧边面板默认关闭,页面上看不到它;下面的代码就是它的全部结构。
<pt-sheet side="right">
  <span slot="title">筛选条件</span>
  <span slot="description">修改后点应用生效。</span>
  <p>正文内容。</p>
  <pt-button slot="footer" variant="secondary">重置</pt-button>
  <pt-button slot="footer" variant="brand">应用</pt-button>
</pt-sheet>

打开与关闭都走 open 属性(show() / hide() 只是它的糖)。关闭后会发 ptClose, detail.reason 说明是怎么关的:close-button / escape / overlay 是用户发起的, api 是调用了 hide()。直接把 open 设为 false 不发 ptClose —— 那是你自己关的, 受控写法下不需要再被告知一次。三个开关事件都不冒泡(弹层天然互相嵌套),外层统一监听要走捕获阶段。

方位与尺寸 ​

side 取 top / right(默认)/ bottom / left:

  • 左右两侧:高度铺满,宽 75%,≥640px 时最多 384px。要别的宽度设 --pt-sheet-size(设了之后宽度与上限都按它)。
  • 上下两侧:宽度铺满,高度随内容。

方位是物理方向,RTL 下不翻转。面板本身就贴着视口边缘,窄屏下不另换形态。 打开时 500ms、关闭时 300ms 从所在的边滑入滑出(遮罩淡入淡出);系统开了「减少动态效果」时不播。

点遮罩默认关闭 ​

与 Modal 相反,面板是临时的旁支内容,点回页面就该回去,所以点遮罩默认关闭(与 Radix 一致)。 面板里有填到一半的表单时关掉它:原生 HTML 写 close-on-overlay="false",框架里 closeOnOverlay={false}。

拦截关闭 ​

用户点 ✕、按 Esc、点遮罩的那一刻,面板先发一个可取消的 ptRequestClose, detail.reason 同上。监听方调用 event.preventDefault(),面板就保持打开,也不会发 ptClose:

tsx
<PtSheet
  open={open}
  onPtRequestClose={event => {
    if (dirty) event.preventDefault();
  }}
  onPtClose={() => setOpen(false)}
>
  …
</PtSheet>

hide() 与直接把 open 设为 false 不经过这个事件,也拦不住。

焦点与层级 ​

与 Modal 共用同一套模态层:打开时焦点落在面板容器本身,Tab 困在面板里,关闭后还给打开它的元素; auto-focus="false" 时焦点不动(在 ptOpen 里自己聚焦),焦点陷阱照样生效。打开期间锁住页面滚动。

面板打开时进浏览器的顶层,不被祖先的 overflow 裁切、不受 transform 与层叠上下文影响。 面板里再打开的下拉、气泡卡片、弹窗都比它后进顶层、盖在它之上;Esc 每次只关最上面那一层。

右上角 ✕ 的读屏名称默认是内置文案「关闭」(随 locale 切换),这一处要说别的话时用 close-label; 不要它时加 hide-close,并自己在 footer 里放关闭入口。

页脚 ​

footer 插槽里的按钮窄屏下纵向排列、后写的在上(主按钮写在后面,窄屏时就在最上面);≥640px 时横排靠行尾。

API ​

属性

属性Attribute类型默认值说明
ariaLabelTextaria-labelstring | undefined—无障碍名称:原生 HTML 里写 aria-label,React / Vue / Angular 包装层里属性名是 ariaLabelText。 没有用 title 插槽时必须给。
autoFocusauto-focusbooleantrue打开时把焦点移进面板(落在面板容器本身)。设为 false 时焦点原地不动 —— 适合在 ptOpen 里自己聚焦某个输入框;焦点陷阱照样生效,第一次 Tab 就会被拉进面板。 默认为真:原生 HTML 里关掉它写 `auto-focus="false"`。
closeLabelclose-labelstring | undefined—右上角关闭按钮的无障碍名称。不设置时用内置文案(`t('modal.close')`,随 locale 切换)
closeOnOverlayclose-on-overlaybooleantrue点遮罩关闭(默认开,与源包 / Radix 一致)。面板里有填到一半的内容时关掉它: 原生 HTML 里写 `close-on-overlay="false"`,框架里 `closeOnOverlay={false}`。
hideClosehide-closebooleanfalse隐藏右上角关闭按钮。隐藏后必须自己在 footer 里提供关闭入口
openopenbooleanfalse是否打开。用户交互时组件自己改写;外部直接赋值立即生效,不发 ptRequestClose / ptClose
sideside"bottom" | "left" | "right" | "top"'right'从哪一侧滑出

事件

事件detail 类型说明
ptClose{ reason: PtSheetCloseReason; }关闭后触发(退场动画开始时,不等它播完),detail 说明是怎么关的:`close-button` / `escape` / `overlay` 是用户发起的(之前的 ptRequestClose 没被取消),`api` 是调用了 hide()。 直接把 open 设为 false **不发**:那是使用方自己关的,受控写法下再回告一次只会多绕一圈。 **不冒泡**:弹层常互相嵌套(弹窗里的面板、面板里的下拉),冒泡的话外层上的监听会收到内层的开关。
ptOpenvoid打开并渲染出来之后触发(交互或属性打开都发) **不冒泡**:弹层常互相嵌套(弹窗里的面板、面板里的下拉),冒泡的话外层上的监听会收到内层的开关。
ptRequestClose{ reason: PtSheetRequestCloseReason; }用户要关闭面板时(点 ✕ / 按 Esc / 点遮罩)、真正关闭之前触发,可取消: `event.preventDefault()` 后面板保持打开,也不会发 ptClose。 `hide()` 与直接把 open 设为 false 不经过它。 **不冒泡**:弹层常互相嵌套(弹窗里的面板、面板里的下拉),冒泡的话外层上的监听会收到内层的开关。

方法

方法说明
hide() => Promise<void>关闭面板(ptClose 的 reason 为 `api`)
show() => Promise<void>打开面板

插槽

名称说明
(默认)正文
description标题下的说明
footer底部操作区。窄屏下按钮纵向排列(后写的在上),≥640px 时靠行尾横排
title标题

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

part说明
base进顶层的最外层容器(铺满视口,包着遮罩与面板)
body正文
close右上角关闭按钮
footer底部
header头部(标题与说明)
overlay遮罩
panel面板本体

CSS 变量

变量说明
--pt-sheet-size左右两侧时的面板宽度。默认 75%、≥640px 时最多 384px;设了之后宽度与上限都按它。上下两侧时不起作用

Apache-2.0 协议开源