ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Vben Drawer 抽屉组件使用指南:从基础用法到数据共享与状态锁定

2026/9/11 9:33:40 拓冰建站 浏览量
Vben Drawer 抽屉组件使用指南:从基础用法到数据共享与状态锁定 Vben Drawer 抽屉组件使用指南从基础用法到数据共享与状态锁定【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin导读本文基于 vue-vben-admin 项目讲解其内置的VbenDrawer抽屉组件位于 packages/core/ui-kit/popup-ui/src/drawer。useVbenDrawer是框架封装的高阶抽屉方案支持自动计算高度、loading、组件抽离、connectedComponent内外组件连接、数据共享以及 5.5.3 版本引入的提交锁定lock/unlock等能力。读完本文你将掌握如何创建最基础的抽屉、如何将抽屉内容抽离并复用、如何在内外组件间共享数据并约束数据类型以及如何用drawerApi和setState动态控制抽屉状态。写在前面如果你觉得现有组件的封装不够理想或者不完全符合你的需求大可以直接使用原生组件亦或亲手封装一个适合的组件。框架提供的组件并非束缚使用与否完全取决于你的需求与自由。基础用法使用useVbenDrawer创建最基础的抽屉。以文档示例 demos/vben-drawer/basic/index.vue 为例script langts setup import { useVbenDrawer, VbenButton } from vben/common-ui; const [Drawer, drawerApi] useVbenDrawer(); /script template div VbenButton click() drawerApi.open()Open/VbenButton Drawer classw-150 title基础示例 drawer content /Drawer /div /template可以看到useVbenDrawer返回一个元组Drawer抽屉组件直接放入模板即可drawerApi抽屉实例方法集合用于控制打开、关闭、更新状态等。抽屉的宽度等布局样式通过class配置例如示例中的w-150宽度 150 单位这与框架中模态框的用法保持一致。组件抽离Drawer 内的内容在真实业务中通常比较复杂因此我们可以将 drawer 内的内容抽离出来也方便复用。通过connectedComponent参数可以将内外组件进行连接而不用其他任何操作。外层入口组件示例 demos/vben-drawer/extra/index.vuescript langts setup import { useVbenDrawer, VbenButton } from vben/common-ui; import ExtraDrawer from ./drawer.vue; const [Drawer, drawerApi] useVbenDrawer({ // 连接抽离的组件 connectedComponent: ExtraDrawer, }); function open() { drawerApi.open(); } /script template div Drawer / VbenButton clickopenOpen/VbenButton /div /template从源码实现看use-drawer.ts当传入connectedComponent时useVbenDrawer会通过provide/inject机制把内部生成的DrawerApi注入到子组件中外层创建一个名为VbenParentDrawer的包装组件将connectedComponent作为其渲染内容并通过USER_DRAWER_INJECT_KEYSymbol(VBEN_DRAWER_INJECT)提供注入数据内层即抽离出的子组件再次调用useVbenDrawer时会通过inject获取到这份注入数据从而拿到同一个extendedApi。这就是“不用其他任何操作”即可完成内外连接的原因。注意如果同时设置了相同的参数那么以内部为准也就是没有设置connectedComponent的代码例如同时设置了onConfirm那么以内部的onConfirm为准。onOpenChange事件除外内外都会触发。提示使用了connectedComponent参数时可以配置destroyOnClose属性来决定当关闭弹窗时是否要销毁connectedComponent组件重新创建connectedComponent组件这将会把其内部所有的变量、状态、数据等恢复到初始状态。源码中onClosed回调会判断mergedOptions.destroyOnClose并通过reCreateDrawer将内部组件重建实现状态复位。自动计算高度弹窗会自动计算内容高度超过一定高度会出现滚动条同时结合loading效果以及使用prepend-footer插槽。完整示例见 demos/vben-drawer/auto-height包含drawer.vue与index.vue两个文件。抽屉默认将内容区域控制在可视范围内内容过多时自动出现滚动条无需手工设置高度。配合loading属性可以在数据加载期间展示加载态避免用户误操作。prepend-footer插槽用于在取消按钮左侧插入额外内容如“重置”按钮关于插槽的完整说明见下文 API 章节。使用 Api通过drawerApi可以调用 drawer 的方法以及使用setState更新 drawer 的状态。示例见 demos/vben-drawer/dynamic。// Drawer 为弹窗组件 // drawerApi 为弹窗的方法 const [Drawer, drawerApi] useVbenDrawer({ // 属性 // 事件 });setState支持两种传参方式直接传PartialDrawerState或传入一个接收prev的函数(prev: DrawerState) PartialDrawerState两种方式都会返回drawerApi本身因此可以链式调用例如drawerApi .setState({ title: 新的标题, loading: true }) .open();数据共享如果你使用了connectedComponent参数那么内外组件会共享数据比如一些表单回填等操作。可以用drawerApi来获取数据和设置数据配合onOpenChange可以满足大部分的需求。示例见 demos/vben-drawer/shared-data。子组件connected 组件内声明数据并暴露 api 的典型写法shared-data/drawer.vuescript langts setup import { ref } from vue; import { useVbenDrawer } from vben/common-ui; interface SharedData { content: string; payload: string; } const data refSharedData(); const [Drawer, drawerApi] useVbenDrawerSharedData({ onCancel() { drawerApi.close(); }, onConfirm() { console.info(onConfirm); }, onOpenChange(isOpen: boolean) { if (isOpen) { data.value drawerApi.getData(); } }, }); defineExpose({ drawerApi }); /script外层组件通过setData传递数据、通过getData读取数据const [Drawer, drawerApi] useVbenDrawer({ connectedComponent: EditDrawer, }); // 打开前写入共享数据 drawerApi.setData({ content: 回填内容, payload: id-001 }).open();典型流程是外层在open()前调用setData写入待回填数据子组件在onOpenChange(isOpen true)时调用getData()取数并渲染到表单。数据类型约束推荐在 connected 子组件中声明一次数据类型并暴露drawerApi外部会从connectedComponent自动推导setData和getData的类型// connected 子组件 const [Drawer, drawerApi] useVbenDrawerEditData(); defineExpose({ drawerApi }); // 外部组件无需重复声明 EditData const [Drawer, drawerApi] useVbenDrawer({ connectedComponent: EditDrawer, });无法从组件公开实例推导时可以显式使用useVbenDrawerEditData()。需要让多个文件共享同一契约时可以在独立模块中预绑定export const useEditDrawer createVbenDrawerEditData();三种方式的优先级为显式泛型、connected component 自动推导、unknown。普通 SFC 通过defineExpose支持自动推导泛型 SFC、函数式组件或被标注为宽Component的组件应使用显式泛型或契约工厂。getData()在尚未调用setData()时返回undefined业务允许null、部分对象等值时需要在数据泛型中准确声明。从源码结构看use-drawer.ts内部通过ResolvedDrawerData条件类型实现推导当调用方未显式传入泛型TData即DrawerDataNotProvided时会回退到从TConnectedComponent的公开实例推导InferDrawerDataTConnectedComponent仓库测试 drawer-types.test.ts 与 fixtures typed-drawer.vue 覆盖了这类类型推导场景。参数优先级VbenDrawer组件对于参数的处理优先级是slotpropsstate通过 api 更新的状态以及useVbenDrawer参数。如果你已经传入了slot或者props那么setState将不会生效这种情况下你可以通过slot或者props来更新状态。全局默认配置如果抽屉的默认行为不符合你的预期可以在对应应用的apps/app/src/bootstrap.ts中修改setDefaultDrawerProps的参数来设置默认属性例如修改默认zIndex等。import { setDefaultDrawerProps } from vben/common-ui; setDefaultDrawerProps({ zIndex: 1200, closeOnClickModal: false, });源码中setDefaultDrawerProps会将传入的属性合并进模块级常量DEFAULT_DRAWER_PROPSuse-drawer.ts随后在每个useVbenDrawer调用中通过mergedOptions将默认配置与当前配置合并。另外源码还默认将全局的 Esc 快捷键配置globalEscapeShortcutKey作为closeOnPressEscape的默认值使抽屉行为与应用级偏好保持一致。APIProps所有属性都可以传入useVbenDrawer的第一个参数中。属性名描述类型默认值appendToMain是否挂载到内容区域默认挂载到 bodybooleanfalseconnectedComponent连接另一个 Drawer 组件Component-destroyOnClose关闭时销毁booleanfalsetitle标题string\|slot-titleTooltip标题提示信息string\|slot-description描述信息string\|slot-isOpen弹窗打开状态booleanfalseloading弹窗加载状态booleanfalseclosable显示关闭按钮booleantruecloseIconPlacement关闭按钮位置left\|rightrightmodal显示遮罩booleantrueheader显示 headerbooleantruefooter显示 footerboolean\|slottrueconfirmLoading确认按钮 loading 状态booleanfalsecloseOnClickModal点击遮罩关闭弹窗booleantruecloseOnPressEscapeesc 关闭弹窗booleantrueconfirmText确认按钮文本string\|slot确认cancelText取消按钮文本string\|slot取消placement抽屉弹出位置left\|right\|top\|bottomrightshowCancelButton显示取消按钮booleantrueshowConfirmButton显示确认按钮booleantrueclassmodal 的 class宽度通过这个配置string-contentClassmodal 内容区域的 classstring-footerClassmodal 底部区域的 classstring-headerClassmodal 顶部区域的 classstring-zIndex抽屉的 ZIndex 层级number1000overlayBlur遮罩模糊度number-appendToMainappendToMain可以指定将抽屉挂载到内容区域打开抽屉时内容区域以外的部分标签栏、导航菜单等等不会被遮挡。默认情况下抽屉会挂载到 body 上。但是挂载到内容区域时作为页面根容器的Page组件需要设置auto-content-height属性以便抽屉能够正确计算高度。Event以下事件只有在useVbenDrawer({ onCancel: () {} })中传入才会生效。事件名描述类型版本限制onBeforeClose关闭前触发返回false或 Promise reject 则禁止关闭()Promiseboolean \| undefined\|boolean\|undefined5.5.2 支持 PromiseonCancel点击取消按钮触发()void---onClosed关闭动画播放完毕时触发()void5.5.2onConfirm点击确认按钮触发()void---onOpenChange关闭或者打开弹窗时触发(isOpen:boolean)void---onOpened打开动画播放完毕时触发()void5.5.2onBeforeClose是拦截关闭的关键钩子返回false或返回一个 reject 的 Promise 时抽屉将禁止关闭常用于“表单未保存确认关闭”等场景5.5.2 版本起支持异步判断。Slots除了上面的属性类型包含slot还可以通过插槽来自定义弹窗的内容。插槽名描述default默认插槽 - 弹窗内容prepend-footer取消按钮左侧center-footer取消按钮和确认按钮中间不使用 footer 插槽时有效append-footer确认按钮右侧close-icon关闭按钮图标extra额外内容标题右侧drawerApi方法描述类型版本限制setState动态设置抽屉状态属性(((prev: DrawerState) PartialDrawerState)\| PartialDrawerState)drawerApi---open打开弹窗()void---close关闭弹窗()void---setData设置共享数据(data:TData)drawerApi---getData获取共享数据()TData\|undefined---useStore获取可响应式状态----lock将抽屉标记为提交中锁定当前状态(isLock:boolean)drawerApi5.5.3unlocklock 方法的反操作解除抽屉的锁定状态也是 lock(false) 的别名()drawerApi5.5.3useStore通过useSelector对抽屉内部的 store 做响应式选择订阅见 use-drawer.ts可用于在抽屉外部响应式地监听抽屉状态。locklock方法用于锁定抽屉的状态一般用于提交数据的过程中防止用户重复提交或者抽屉被意外关闭、表单数据被改变等等。当处于锁定状态时抽屉的确认按钮会变为 loading 状态同时禁用取消按钮和关闭按钮、禁止 ESC 或者点击遮罩等方式关闭抽屉、开启抽屉的 spinner 动画以遮挡弹窗内容。调用close方法关闭处于锁定状态的抽屉时会自动解锁。要主动解除这种状态可以调用unlock方法或者再次调用lock方法并传入false参数。典型提交场景用法async function handleSubmit() { drawerApi.lock(); // 锁定确认按钮 loading、禁止关闭 try { await submitForm(); drawerApi.close(); // close 会自动解锁 } finally { drawerApi.unlock(); // 兜底解锁 } }仓库针对该功能的交互测试见 drawer-interaction.test.ts。小结VbenDrawer将抽屉的“展示层”与“控制层”解耦展示层由Drawer组件负责控制层由drawerApi统一管理配合connectedComponent的provide/inject机制实现了内外组件零成本连接与类型安全的数据共享。无论是简单的确认抽屉、复杂的表单回填还是需要防重复提交的提交锁定场景都可以基于这套 API 快速落地。若默认行为不符预期优先通过drawerApi.setState或全局的setDefaultDrawerProps进行调整保持业务代码的简洁。【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. Its fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考