首页
/ Ant Design Drawer 可拖拽调整尺寸(resizable)完整实战指南

Ant Design Drawer 可拖拽调整尺寸(resizable)完整实战指南

2026-09-07 12:08:56作者:邵娇湘

Drawer(抽屉)通常以固定尺寸从屏幕边缘滑出,但当面板内容较长、用户需要更大可视区域或需要自由对比上下文时,固定尺寸会成为体验瓶颈。antd 从 6.0.0 起为 Drawer 引入了 resizable 能力,允许用户直接拖拽面板边缘实时调整抽屉的宽度或高度。本篇将以 resizable 示例文档 及其 示例源码 为主体,结合 Drawer 组件实现源码与样式代码,完整讲解可调整尺寸抽屉的用法、参数语义、受控尺寸同步与拖拽条样式原理,帮助你快速在自己的项目中落地"拖拽改变抽屉大小"的交互。

一、功能定位:从固定尺寸到可拖拽尺寸

普通的 Drawer 通过 size(或已被 size 取代的 width/height)固定面板尺寸,用户无法改变。而开启 resizable 后,抽屉会在可拖拽的边缘(取决于 placement)渲染一条透明的拖拽热区(dragger),用户按住并拖动即可改变面板尺寸。官方对该 demo 的定义是:

可调整大小的抽屉,允许通过拖拽边缘来调整抽屉的宽度或高度。(Resizable drawer that allows users to adjust the drawer's width or height by dragging the edge.)

从源码看,该能力面向横向与纵向四个方向均生效:placementleft / right 时拖拽改变的是宽度,为 top / bottom 时拖拽改变的是高度——这正是 API 文档中 maxSize 描述为"可拖拽的最大尺寸(宽度或高度,取决于 placement)"的原因(见 index.en-US.md)。

版本前提:resizable 对象形式自 6.0.0 引入,纯布尔形式 resizable 自 6.1.0 起可用;maxSize 同样为 6.0.0。使用前请确认项目的 antd 版本不低于 6.0.0(示例文档也标注了 version="6.0.0")。

二、最小可用示例与逐行解析

resizable.tsx 是一个同时演示"四个方向 + 实时尺寸展示 + 切换方向自动复位"的完整示例,其核心代码如下:

import React, { useState } from 'react';
import type { DrawerProps, RadioChangeEvent } from 'antd';
import { Button, Drawer, Radio, Space } from 'antd';

const App: React.FC = () => {
  const [open, setOpen] = useState(false);
  const [placement, setPlacement] = useState<DrawerProps['placement']>('right');
  const [size, setSize] = useState(256);

  const onChange = (e: RadioChangeEvent) => {
    setSize(256);                      // 切换方向时把尺寸重置为初始值
    setPlacement(e.target.value);
  };

  return (
    <>
      <Space style={{ marginBottom: 16 }}>
        <Radio.Group
          value={placement}
          onChange={onChange}
          options={['top', 'right', 'bottom', 'left'].map((pos) => ({
            label: pos,
            value: pos,
          }))}
        />
        <Button type="primary" onClick={() => setOpen(true)}>
          Open Drawer
        </Button>
      </Space>
      <div>Current size: {size}px</div>
      <Drawer
        title="Resizable Drawer"
        placement={placement}
        onClose={() => setOpen(false)}
        open={open}
        key={placement}
        size={size}
        resizable={{
          onResize: (newSize) => setSize(newSize),
        }}
      >
        <p>Drag the edge to resize the drawer</p>
        <p>Current size: {size}px</p>
      </Drawer>
    </>
  );
};

export default App;

该示例中值得注意的四个细节:

  1. size 为受控数值:初始为 256,与常见的预设字符串('default' / 'large')不同,这里直接以数字作为当前尺寸。size 属性支持 'default' | 'large' | number | string,其中 number 会在源码中被直接使用。
  2. resizable 传入对象并回调 onResize:拖拽过程中把最新尺寸写回 state,再通过 size={size} 回传给 Drawer,形成"拖哪显示哪"的实时受控闭环;页面顶部 Current size: {size}px 因此能同步显示实时尺寸。
  3. key={placement}:切换 placement 时强制重建抽屉实例,避免面板残留旧方向的状态,是 demo 切换方向的常用手法。
  4. 切换方向先 setSize(256):由于横向(宽)与纵向(高)是两种尺寸语义,demo 在切换方向时主动将尺寸复位,避免上个方向的尺寸直接套用到新方向。

三、相关 API 与 ResizableConfig 详解

可拖拽尺寸涉及的 Drawer 配置项在 API 文档 中有完整定义,下面结合源码逐项说明。

3.1 resizable:是否启用拖拽改变尺寸

resizable?: boolean | DrawerResizableConfig;
  • 传入 true 即启用最基础的拖拽调整能力,不做任何受控或事件绑定;
  • 传入 ResizableConfig 对象时,可在拖拽生命周期中插入回调(详见 3.3)。

Drawer.tsx 中,DrawerResizableConfig 的 TypeScript 定义与官方 ResizableConfig 完全一致,包含三个可选回调。组件接收 resizable 后,通过条件展开透传给底层 @rc-component/drawer

<RcDrawer
  {...rest}
  size={drawerSize}
  defaultSize={defaultSize}
  ...
  {...(resizable ? { resizable } : {})}
>

也就是说,antd 的 Drawer 是"透传者"角色——真正的拖拽手势、方向判定与尺寸运算由 @rc-component/drawer 完成(DrawerProps 中已通过 Omit 移除底层同名类型,再以 antd 语义重新声明,见 Drawer.tsx)。

3.2 size 与 maxSize:受控尺寸与上限约束

参数 说明 类型 默认值
size 预设抽屉宽度(或高度),default 378px、large 736px,或自定义数值/字符串 'default' | 'large' | number | string 'default'
maxSize 可拖拽的最大尺寸(宽度或高度,取决于 placement),用于限制拖拽上限 number -

size 的分发逻辑集中在 Drawer.tsxdrawerSize 计算中:

  • size 为数字时原样使用(如 demo 中的 256);
  • size === 'large' 映射为 736size === 'default' 映射为常量 DEFAULT_SIZE = 378(见 Drawer.tsx);
  • 数字形式字符串会被 Number() 转换;
  • left / right 方向,回退读取旧的 width;对 top / bottom 方向,回退读取旧的 height(两者均已标记 deprecated,建议统一改用 size)。

因此在实际项目中,若要限制用户拖拽范围,可同时传入初始 sizemaxSize,例如一个"右侧抽屉最小 378、最大 736"的约束可用 size={378} maxSize={736} resizable 表达。

3.3 ResizableConfig:拖拽生命周期回调

参数 说明 类型 版本
onResizeStart 开始拖拽调整大小时的回调 () => void 6.0.0
onResize 拖拽调整大小时的回调 (size: number) => void 6.0.0
onResizeEnd 结束拖拽调整大小时的回调 () => void 6.0.0

三者的应用场景非常清晰:

  • onResizeStart:进入拖拽态时触发,适合做一次性的 UI 反馈(如给面板加个类名提示"正在调整",或记录拖拽前尺寸用于撤销/还原);
  • onResize:拖拽过程中高频触发,参数为当前像素尺寸。demo 正是靠它驱动 setSize 实现受控实时显示;若要"松手后再持久化",也可在此做节流记录;
  • onResizeEnd:鼠标/手指松开、本次拖拽结束时触发,适合把最终尺寸持久化(如写入 localStorage 或提交到后端),避免 onResize 高频写入。

典型用法示例:

const [size, setSize] = useState(520);

<Drawer
  open={open}
  size={size}
  maxSize={900}
  resizable={{
    onResizeStart: () => setIsDragging(true),
    onResize: (newSize) => setSize(newSize),
    onResizeEnd: () => {
      setIsDragging(false);
      // 例如:persistSize(size);
    },
  }}
/>

四、源码级原理:拖拽指示条(dragger)如何渲染与呈现

resizable 开启且抽屉打开时,Drawer 的语义化 DOM 中会多出一个 dragger 结构。测试快照中可看到实际渲染的类名形态(见 demo-extend.test.tsx.snap):

ant-drawer-resizable-dragger ant-drawer-resizable-dragger-right ant-drawer-resizable-dragger-horizontal

类名组合为 ant-drawer-resizable-dragger + 方向 + 轴类型,其中 -right 表示吸附在右侧、-horizontal 表示水平方向的拖拽轴(即调整宽度)。antd 同时把 dragger 纳入语义化样式体系:classNames.draggerstyles.dragger 都会在 Drawer.tsx 中合并后传给底层 RcDrawer,因此开发者可用 classNames={{ dragger: 'my-dragger' }}styles={{ dragger: { background: 'red' } }} 精确命中拖拽条。

拖拽条的位置与指针样式在 style/index.ts 中按四方向分别声明,例如:

  • dragger-left / dragger-right:垂直铺满 top: 0; bottom: 0,宽度为 draggerSizecursor: col-resize,吸附在边缘对应侧;
  • dragger-top / dragger-bottom:横向铺满,高度为 draggerSizecursor: row-resize

基础样式(对所有方向生效)包括:position: absolute、透明背景 transparentuserSelect: none 防止拖拽时选中文本。交互反馈靠两层状态区分(见 style/index.ts):

  • 悬停态 &:hover:背景变为 colorPrimaryopacity: 0.2,提示"此处可拖拽";
  • 拖拽态 &-dragging:背景为 colorPrimaryopacity: 0.3,明确反馈"正在调整"。

拖拽热区的宽度来自 token draggerSize,默认值为 4(见 style/index.ts),既足够细而不抢视觉,又保留了够用的命中区域,是抽屉可拖拽交互的"隐形把手"设计。

五、落地实践要点

5.1 让拖拽尺寸在页面其他位置可见

参考 demo 的做法,把 size 提升到公共 state,既作为 Drawer 的受控值,也可用于页面展示(demo 顶部 Current size: {size}px)。注意 onResize 是拖拽期间的实时回调,直接 setState 即可,无需防抖——React 会按帧合并渲染。

5.2 切换方向时重置尺寸

widthheight 是两套维度,从一个 right 抽屉切到 bottom 抽屉时,若沿用上一次的宽度数值作为高度通常不合理。demo 的策略值得直接复用:切换前 setSize(256),并配合 key={placement} 让抽屉重建。

5.3 尺寸约束

  • maxSize 限制拖拽上限,避免面板过大挤压主内容;
  • 拖拽下限取决于抽屉自身的样式约束(如内部内容的最小宽度),不需要额外处理。

5.4 渲染结构引用

由于 dragger 是 Drawer 的语义化子结构,凡是需要自定义拖拽条观感(宽度、颜色、悬停态)或做自动化测试定位(如断言 ant-drawer-resizable-dragger 存在)的场景,都可以直接以该 DOM 类名为锚点。在 antd 自带的测试体系中,该 demo 已通过 demo.test.ts、快照测试与语义测试的多重校验,可当作"用法正确性"的参照实现。

六、小结

一句话总结本指南:resizable + 受控 size + 生命周期回调,即可获得实时、可约束、可持久化的拖拽调整尺寸抽屉。实现上 antd Drawer 将 resizable 透传给 @rc-component/drawer 完成手势计算,自身负责在四个方向渲染对应的 dragger 热区,并通过语义化的 classNames.dragger / styles.dragger 与 token draggerSize 暴露定制入口。若需继续深入,可前往 Drawer.tsx 阅读透传与尺寸计算逻辑,在 style/index.ts 查看拖拽条样式实现,或在 Drawer 完整 API 中查阅 resizablemaxSizesize 的完整说明与其他相关属性。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388