Ant Design Drawer 基础抽屉实战:从右侧滑出的受控面板与完整 API 解析
2026/9/18 21:25:21 网站建设 项目流程

Ant Design Drawer 基础抽屉实战:从右侧滑出的受控面板与完整 API 解析

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design

抽屉(Drawer)是 Ant Design 中用于承载临时任务与附加内容的浮层组件。本文以仓库中的「基础抽屉」官方示例(components/drawer/demo/basic-right.md 及其配套代码 components/drawer/demo/basic-right.tsx)为骨架,讲解如何实现"点击按钮抽屉从右滑出、点击遮罩区关闭"这一最典型的应用场景,并向下深挖组件源码、测试用例与全部 API 参数,帮助你从"能跑通示例"进阶到"理解抽屉的完整行为模型"。

基础抽屉:最小可运行实现

官方示例的核心语义是:基础抽屉,点击触发按钮抽屉从右滑出,点击遮罩区关闭。完整代码如下(摘自 basic-right.tsx):

import React, { useState } from 'react'; import { Button, Drawer } from 'antd'; const App: React.FC = () => { const [open, setOpen] = useState(false); const showDrawer = () => { setOpen(true); }; const onClose = () => { setOpen(false); }; return ( <> <Button type="primary" onClick={showDrawer}> Open </Button> <Drawer title="Basic Drawer" onClose={onClose} open={open}> <p>Some contents...</p> <p>Some contents...</p> <p>Some contents...</p> </Drawer> </> ); }; export default App;

这个示例虽然短小,却覆盖了 Drawer 的核心使用范式,可拆解为三个要点:

  1. 受控开关open属性决定抽屉是否可见,由useState(false)维护。点击按钮调用showDraweropen置为true,抽屉即从右侧滑出。
  2. 关闭回调onClose在"点击遮罩层、点击关闭图标或按 Esc"等场景被触发,回调中把open置回falseonClose只负责"通知",真正关闭仍需你同步状态,这是典型的受控组件设计。
  3. 内容区title渲染标题栏,children(三个<p>占位内容)渲染在面板主体区域。

从 v5 开始,控制开关的受控属性统一为open。v4 时代的visible已被标记为 deprecated(@deprecated Please use open instead),afterVisibleChange亦被afterOpenChange取代,见 components/drawer/index.tsx 的类型定义。

点击遮罩关闭与 Esc 关闭的行为模型

示例描述"点击遮罩区关闭"并非魔法,而是由两个默认值驱动的:

  • mask(默认true:是否展示遮罩层。示例未显式传入,因此默认有半透明遮罩。
  • maskClosable(默认true:点击蒙层是否允许关闭。示例未显式传入,因此点击遮罩会触发onClose
  • keyboard(默认true:是否支持键盘Esc关闭。

也就是说,基础示例"点击遮罩区关闭"完全来自默认参数;如果你希望遮罩不可点击关闭,只需显式设置maskClosable={false}。需要无遮罩模式时可参考仓库中的 no-mask.md 演示(对应源码中'no-mask': !mask的类名拼接,见 components/drawer/index.tsx)。

滑出方向与尺寸:默认从右、默认 378px

示例标题为"基础抽屉",之所以"从右滑出",是因为placement的默认值为right。可取值有top/right/bottom/left,官方另提供 placement.md 演示用Radio.Group动态切换四个方向:

const [placement, setPlacement] = useState<DrawerProps['placement']>('left'); // ... <Drawer title="Basic Drawer" placement={placement} closable={false} onClose={onClose} open={open}>

方向与尺寸的搭配规则如下:

  • right/left时使用width控制宽度;top/bottom时使用height控制高度。
  • width默认378height默认378(单位像素,也支持字符串如'50%')。
  • 预设尺寸size'default'(378px)或'large'(736px),优先级低于显式传入的width/height

这一合并逻辑在源码中有清晰的体现(components/drawer/index.tsx):

const mergedWidth = React.useMemo<string | number>( () => width ?? (size === 'large' ? 736 : 378), [width, size], ); const mergedHeight = React.useMemo<string | number>( () => height ?? (size === 'large' ? 736 : 378), [height, size], );

即:显式width/height优先,未传时按sizelarge: 736default: 378。预设宽度的演示见 size.md。

Drawer 完整 API 参数速查

下表完整继承自官方文档 components/drawer/index.zh-CN.md,并结合源码补充了默认值与版本说明:

参数说明类型默认值版本
autoFocus抽屉展开后是否将焦点切换至其 DOM 节点booleantrue4.17.0
afterOpenChange切换抽屉时动画结束后的回调function(open)-
classNameDrawer 容器外层 className 设置,如需设置最外层请使用 rootClassNamestring-
classNames语义化结构 classNameRecord<SemanticDOM, string>-5.10.0
closeIcon自定义关闭图标;5.7.0 起设置为nullfalse可隐藏关闭按钮ReactNode<CloseOutlined />
destroyOnClose关闭时销毁 Drawer 里的子元素booleanfalse
extra抽屉右上角的操作区域ReactNode-4.17.0
footer抽屉的页脚ReactNode-
forceRender预渲染 Drawer 内元素booleanfalse
getContainer指定 Drawer 挂载的节点并在容器内展现,false为挂载在当前位置HTMLElement | () => HTMLElement | Selectors | falsebody
height高度,placementtopbottom时使用string | number378
keyboard是否支持键盘 esc 关闭booleantrue
mask是否展示遮罩booleantrue
maskClosable点击蒙层是否允许关闭booleantrue
placement抽屉的方向top|right|bottom|leftright
push多层 Drawer 的推动行为boolean | { distance: string | number }{ distance: 180 }4.5.0+
rootStyle最外层容器样式,与style的区别是作用节点包括maskCSSProperties-
size预设抽屉宽度(或高度),default 378px / large 736px'default' | 'large''default'4.17.0
styleDrawer 容器样式,仅需设置内容部分请使用bodyStyleCSSProperties-
styles语义化结构 styleRecord<SemanticDOM, CSSProperties>-5.10.0
title标题ReactNode-
loading显示骨架屏booleanfalse5.17.0
openDrawer 是否可见boolean-
width宽度string | number378
zIndex设置 Drawer 的 z-indexnumber1000
onClose点击遮罩层、关闭图标或取消按钮时的回调function(e)-
drawerRender自定义渲染抽屉(node: ReactNode) => ReactNode-5.18.0

关于loading属性有一处官方明确的演进记录:自5.17.0提供loading后,5.18.0修复了设计失误,将内置的 Spin 组件替换为 Skeleton 组件,同时收窄了loading的类型范围(仅接收 boolean)。在源码 DrawerPanel.tsx 中可以看到,loadingtrue时 body 内渲染的是 5 行 paragraph 的Skeleton

{loading ? ( <Skeleton active title={false} paragraph={{ rows: 5 }} className={`${prefixCls}-body-skeleton`} /> ) : ( children )}

面板结构:header / body / footer 三段式

抽屉内容面板由 DrawerPanel.tsx 组装,结构固定为三段:

  • header:当title或关闭按钮存在时渲染,包含关闭图标(closeIcon,默认<CloseOutlined />,经useClosable合并)、标题与右侧extra操作区;仅有关闭按钮而无标题、无 extra 时会附加-header-close-only类(见 DrawerPanel.tsx)。
  • body:主体内容区,默认渲染childrenloading时替换为 Skeleton。
  • footer:仅当传入footer属性时渲染页脚节点。

三个区域都支持通过classNames(语义化 className)与styles(语义化 style)精确控制样式,这正是 5.10.0 引入的 Semantic DOM 能力,示例见 classNames.md。另注意官方提示:v5 使用rootClassNamerootStyle配置最外层元素样式,v4 的className/style语义改为作用于 Drawer 窗体本身,以与 Modal 对齐。

源码级原理:尺寸合并、动画、push 与 zIndex

在 components/drawer/index.tsx 中,可以观察到Drawer是对rc-drawer的封装,几个值得注意的实现细节:

  • 动画配置maskMotionpanelMotion均设置了motionAppear / motionEnter / motionLeavemotionDeadline: 500,其中面板动画按placement区分(panel-motion-${motionPlacement}),这解释了"从右滑出"的滑入动画来源(index.tsx)。
  • 多层抽屉推动push默认值为{ distance: 180 }defaultPushState),当存在多层 Drawer 时,下层会被向同方向推动 180px,演示见 multi-level-drawer.md。
  • zIndex 管理:通过useZIndex('Drawer', rest.zIndex)获取层级,并与zIndexContext.Provider联动,保证 Drawer、Modal、Popover 等浮层之间的遮挡顺序正确。
  • ContextIsolator:渲染时用<ContextIsolator form space>隔离 Form 与 Space 上下文,避免抽屉内容意外继承外层表单行为。
  • 废弃属性告警:开发环境下会对visibleafterVisibleChangeheaderStylebodyStylecontentWrapperStylemaskStyledrawerStyle等旧属性逐一发出deprecated警告,引导迁移到openafterOpenChangestyles.*新写法(index.tsx)。

测试如何验证"基础抽屉"

仓库为抽屉组件维护了多层测试,可作为行为契约参考:

  • demo.test.ts 通过demoTest('drawer')对所有 demo 做冒烟渲染,保证示例可运行。
  • demo-extend.test.tsx 在 mockrc-drawer(强制open: truegetContainer: false、禁用动画)后对 demo 进行更严格的交互测试。
  • Drawer.test.tsx 覆盖了render correctlygetContainer返回 undefined/false、render top drawerplacement="top"height)、RTL 方向等核心行为,其中triggerMotion通过模拟遮罩与面板的animationEnd完成动画推进。

这些测试共同印证了示例中的行为:打开由open驱动、方向由placement决定、遮罩点击与 Esc 通过onClose通知状态更新。

从基础示例出发的下一步

基础抽屉解决的是"临时任务浮层"这一最小诉求。当业务场景变复杂时,官方演示集还提供了成套方案,均可在仓库中直接查看:

  • 表单放入抽屉:form-in-drawer.md
  • 信息预览型抽屉:user-profile.md
  • 多层抽屉联动:multi-level-drawer.md
  • 渲染在当前 DOM(getContainer={false}):render-in-current.md
  • 预设宽度:size.md

掌握本文的基础范式(受控open+onClose回调 + 默认placement="right"+ 默认宽高 378px),再配合完整 API 表与源码实现细节,即可在项目中自如地驾驭这一"从屏幕边缘滑出的浮层面板"。

【免费下载链接】ant-designAn enterprise-class UI design language and React UI library项目地址: https://gitcode.com/gh_mirrors/ant/ant-design

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询