ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

VueUse useConfirmDialog 深度指南:用事件钩子与 Promise 优雅管理模态框确认链

VueUse useConfirmDialog 深度指南:用事件钩子与 Promise 优雅管理模态框确认链 前端【免费下载链接】vueuseCollection of essential Vue Composition Utilities for Vue 3项目地址https://gitcode.com/gh_mirrors/vu/vueuse点击查看免费下载导读useConfirmDialog是 VueUse 核心包vueuse/core中用于创建确认对话框的工具函数。它以事件钩子event hook为骨架为模态框、弹窗、登录验证等需要用户确认的业务逻辑提供一套简洁的状态管理方案reveal()打开对话框并返回一个 Promiseconfirm()/cancel()负责关闭对话框并触发对应的钩子最终该 Promise 以带isCanceled标志的结果兑现。读完本文你将掌握它的三个核心动作、两种消费模式钩子式与 Promise 式、类型签名以及如何通过组合多个实例构建“确认后继续确认”的对话框链。本文基于当前仓库实现文档见 skills/vueuse-functions/references/useConfirmDialog.md 与 packages/core/useConfirmDialog/index.md源码见 packages/core/useConfirmDialog/index.ts配套测试见 packages/core/useConfirmDialog/index.browser.test.ts。核心概念三个动作与三个钩子useConfirmDialog的设计围绕“打开—确认—取消”三种用户动作展开每种动作对应一个函数同时对应一个事件钩子reveal()触发onReveal钩子并将revealed.value置为true。返回一个 Promise该 Promise 最终由confirm()或cancel()来兑现resolve。confirm()将isRevealed.value置为false并触发onConfirm钩子同时以{ data, isCanceled: false }兑现reveal()返回的 Promise。cancel()将isRevealed.value置为false并触发onCancel钩子同时以{ data, isCanceled: true }兑现reveal()返回的 Promise。返回对象包含六个成员isRevealedComputedRefboolean对话框可见状态、reveal、confirm、cancel三个控制函数以及onReveal、onConfirm、onCancel三个钩子注册函数。模板中可以直接使用这些函数与状态钩子则为对话框的业务逻辑提供了一个干净的骨架。源码视角从创建到兑现的完整调用链打开 packages/core/useConfirmDialog/index.ts 可以看到实现非常精简全部逻辑约 40 行const confirmHook: EventHook createEventHookConfirmData() const cancelHook: EventHook createEventHookCancelData() const revealHook: EventHook createEventHookRevealData() let _resolve: (arg0: UseConfirmDialogRevealResultConfirmData, CancelData) void noop const reveal (data?: RevealData) { revealHook.trigger(data) revealed.value true return new PromiseUseConfirmDialogRevealResultConfirmData, CancelData((resolve) { _resolve resolve }) } const confirm (data?: ConfirmData) { revealed.value false confirmHook.trigger(data) _resolve({ data, isCanceled: false }) } const cancel (data?: CancelData) { revealed.value false cancelHook.trigger(data) _resolve({ data, isCanceled: true }) }关键实现细节底层依赖createEventHook三个钩子均由 VueUse 的createEventHook创建。该工具内部用Set维护回调函数集合on(fn)注册回调并返回带off()的取消句柄且通过tryOnScopeDispose在组件作用域销毁时自动解绑——因此你无需手动清理onConfirm之类的监听。trigger(...args)使用Promise.all并行执行所有回调。内部保存 Promise 的 resolve 引用reveal()创建 Promise 时把resolve存到模块内的_resolve变量之后confirm()/cancel()调用_resolve(...)完成兑现。也就是说同一个实例在同一时刻只支持一个待决的 Promise下一次reveal()会覆盖上一次的 resolve 引用。无副作用标记函数声明上方标有__NO_SIDE_EFFECTS__配合 VueUse 的按需导出机制允许构建工具安全地将其 tree-shake。默认参数revealed参数默认为shallowRef(false)也就是说不传参也能独立使用但传入外部ShallowRefboolean后对话框的可见状态便由外部完全掌控见下文“传入自定义 ref”。基础用法一纯钩子驱动模态框如果习惯命令式地控制界面可以直接用钩子驱动模板。以下是最基础的用法与官方文档示例一致script setup langts import { useConfirmDialog } from vueuse/core const { isRevealed, reveal, confirm, cancel, onReveal, onConfirm, onCancel } useConfirmDialog() /script template button clickreveal Reveal Modal /button teleport tobody div v-ifisRevealed classmodal-bg div classmodal h2Confirm?/h2 button clickconfirm Yes /button button clickcancel Cancel /button /div /div /teleport /template在这个例子中点击“Reveal Modal”调用reveal()isRevealed变为true模板中的v-ifisRevealed让模态框显示用户点击“Yes”调用confirm()、点击“Cancel”调用cancel()两者都会把isRevealed置回false。teleport tobody是 Vue 内置传送门用于将模态框渲染到body下规避父级容器的overflow、z-index等样式干扰。onReveal/onConfirm/onCancel钩子可以单独注册副作用。测试用例 packages/core/useConfirmDialog/index.browser.test.ts 明确验证了时序语义onReveal的回调在对话框打开时立刻执行且仅在reveal()时触发测试should execute onReveal fn on open dialogonConfirm的回调只有在调用confirm()之后才执行reveal()本身不会触发它测试should execute a callback inside onConfirm hook only after confirmingonCancel同理只有cancel()才触发测试should execute a callback inside onCancel hook only after canceling dialog。基础用法二Promise 驱动的结果消费如果你更喜欢以 Promise 方式等待用户决策reveal()返回的 Promise 会在confirm()/cancel()时兑现兑现结果为type UseConfirmDialogRevealResultC, D | { data?: C isCanceled: false } | { data?: D isCanceled: true }其中isCanceled是布尔字面量类型判别discriminated union 判别字段confirm()兑现为{ data, isCanceled: false }cancel()兑现为{ data, isCanceled: true }。因此解构后可以直接用if (!isCanceled)进行类型收窄TypeScript 会据此推断data的精确类型。Promise 风格用法如下script setup langts import { useConfirmDialog } from vueuse/core const { isRevealed, reveal, confirm, cancel, } useConfirmDialog() async function openDialog() { const { data, isCanceled } await reveal() if (!isCanceled) console.log(data) } /script template button clickopenDialog Show Modal /button teleport tobody div v-ifisRevealed classmodal-layout div classmodal h2Confirm?/h2 button clickconfirm(true) Yes /button button clickconfirm(false) No /button /div /div /teleport /template这里用confirm(true)/confirm(false)把布尔结果作为data传给调用方openDialog中await reveal()拿到{ data, isCanceled }当用户点“Yes”时data true点“No”时data false点“Cancel”时isCanceled true。测试should return promise that will be resolved on confirm()与should return promise that will be resolved on cancel()分别在setTimeout中调用confirm(true)/cancel(true)后await reveal()验证了data与isCanceled的取值。confirm(data)与cancel(data)可以携带任意类型的数据ConfirmData/CancelData泛型默认any这些数据一方面传给onConfirm/onCancel钩子回调另一方面作为 Promise 的data字段返回一条数据通路贯穿钩子与 Promise 两种消费方式。传入自定义 ref把可见状态交给外部useConfirmDialog接受一个可选的ShallowRefboolean参数用于接管对话框的可见状态export declare function useConfirmDialog RevealData any, ConfirmData any, CancelData any, ( revealed?: ShallowRefboolean, ): UseConfirmDialogReturnRevealData, ConfirmData, CancelData未传参时内部默认shallowRef(false)。传入外部 ref 的意义在于你可以用其他逻辑直接控制该 ref例如v-model绑定、路由守卫联动、按 Esc 键关闭等isRevealed只是computed(() revealed.value)的派生状态注意该参数是ShallowRef即仅浅层响应适合布尔开关这类简单值。官方文档对revealed参数的注释是一个处理模态窗口的booleanref。源码中reveal()置true、confirm()/cancel()置false测试如should open the dialog and close on confirm正是传入外部shallowRef(false)后断言其值在调用前后翻转的。进阶实战用多个实例串联确认对话框链useConfirmDialog的文档定义就是“support modals and confirmation dialog chains”——对话框链。当某个操作需要多步确认例如“是否继续”“最终确认”时可以创建多个实例通过钩子把它们的reveal/confirm串起来。仓库自带的可运行示例 packages/core/useConfirmDialog/demo.vue 完整演示了这一模式script setup langts import { useConfirmDialog } from vueuse/core import { shallowRef } from vue const message shallowRef() const revealed1 shallowRef(false) const revealed2 shallowRef(false) const dialog1 useConfirmDialog(revealed1) const dialog2 useConfirmDialog(revealed2) dialog1.onReveal(() { message.value Modal is shown! }) dialog1.onConfirm(() { dialog2.reveal() // 第一个对话框确认后打开第二个 }) dialog1.onCancel(() { message.value Canceled! }) dialog2.onReveal(() { message.value Second modal is shown! }) dialog2.onConfirm((result) { if (result) message.value Confirmed! else message.value Rejected! }) dialog2.onCancel(() { dialog1.reveal() // 第二个对话框取消后回到第一个 message.value Canceled! }) /script模板中两个对话框分别用v-ifrevealed1/v-ifrevealed2控制显示按钮通过:disabledrevealed1 || revealed2防止打开入口被重复点击。整个流程形成了一条可回退的确认链点击按钮 →dialog1.reveal()→ 第一个对话框出现点“OK” →dialog1.confirm()→onConfirm触发dialog2.reveal()→ 第二个对话框出现第二个对话框点“Confirm” / “Reject” →dialog2.confirm(true / false)→onConfirm拿到布尔结果分别提示“Confirmed!” / “Rejected!”第二个对话框点“Cancel” →dialog2.cancel()→onCancel触发dialog1.reveal()流程回退到第一个对话框。这种“链式确认”的典型业务场景包括删除前的二次确认、多步骤向导式操作、支付前的复核弹窗等。相比手写多套ref 事件回调useConfirmDialog让每一步的状态与流转逻辑都收敛在各自实例的钩子中可读性和可维护性都更好。类型声明一览以下是官方文档中完整的类型声明与源码 packages/core/useConfirmDialog/index.ts 保持一致export type UseConfirmDialogRevealResultC, D | { data?: C isCanceled: false } | { data?: D isCanceled: true } export interface UseConfirmDialogReturnRevealData, ConfirmData, CancelData { /** Revealing state */ isRevealed: ComputedRefboolean /** * Opens the dialog. * Creates a promise and returns it. Triggers onReveal hook. */ reveal: ( data?: RevealData, ) PromiseUseConfirmDialogRevealResultConfirmData, CancelData /** * Confirms and closes the dialog. Triggers a callback inside onConfirm hook. * Resolves promise from reveal() with data and isCanceled ref with false value. * Can accept any data and pass it to onConfirm hook. */ confirm: (data?: ConfirmData) void /** * Cancels and closes the dialog. Triggers a callback inside onCancel hook. * Resolves promise from reveal() with data and isCanceled ref with true value. * Can accept any data and pass it to onCancel hook. */ cancel: (data?: CancelData) void /** Event Hook to be triggered right before dialog creation. */ onReveal: EventHookOnRevealData /** Event Hook to be called on confirm(). Gets data object from confirm function. */ onConfirm: EventHookOnConfirmData /** Event Hook to be called on cancel(). Gets data object from cancel function. */ onCancel: EventHookOnCancelData }其中EventHookOnT来自vueuse/shared签名是(fn: CallbackT) { off: () void }——注册回调后返回off()以便在需要时手动解绑不过组件销毁时tryOnScopeDispose已自动处理。useConfirmDialog的泛型RevealData/ConfirmData/CancelData分别约束reveal、confirm、cancel携带的数据类型默认均为any实践中建议按业务需要显式指定以获得更好的类型提示与收窄效果。使用要点与注意事项安装与导入useConfirmDialog从vueuse/core包导出见 packages/core/index.ts 的export * from ./useConfirmDialog。配合 Vite/Vue 3 项目直接pnpm add vueuse/core后import { useConfirmDialog } from vueuse/core即可。同一时刻一个待决 Promise_resolve是实例内部共享的单个变量连续调用reveal()会覆盖前一个 Promise 的 resolve 引用。若业务上需要并发打开多个互不干扰的对话框应创建多个useConfirmDialog()实例如上面 demo 的做法。钩子与 Promise 可混用confirm(data)/cancel(data)的数据同时流向钩子回调与 Promise 的data字段两种消费方式并不互斥可按场景自由组合。关闭动作永远成对模板中务必确保“确认”和“取消”两条关闭路径都存在否则reveal()的 Promise 会一直挂起调用方await将无法返回。无需手动清理监听on注册的回调借助tryOnScopeDispose在当前组件作用域销毁时自动移除避免内存泄漏。赞分享前端【免费下载链接】vueuseCollection of essential Vue Composition Utilities for Vue 3项目地址https://gitcode.com/gh_mirrors/vu/vueuse点击查看免费下载相关推荐xi-editor LSP集成指南5步为编辑器搭建语言服务器的智能桥梁xi editor LSP集成指南5步为编辑器搭建语言服务器的智能桥梁 本文带你完成 xi editor 的 LSP 集成 通过 LSP 插件xi lsp开发工具useConfirmDialog用事件钩子与 Promise 优雅编排 Vue 3 确认弹窗useConfirmDialog用事件钩子与 Promise 优雅编排 Vue 3 确认弹窗 导读 useConfirmDialog 是 VueUse 核心包前端开源录屏工具 Cap 怎么跑起来从安装到自托管的完整指南开源录屏工具 Cap 怎么跑起来从安装到自托管的完整指南 Cap 是一款免费开源的录屏工具也是可自托管的 Loom 替代方案屏幕、摄像头、麦克风一起录录前端上一篇three.quarks加载与导出JSON格式与QuarksLoader使用详解下一篇WeChatMsg 使用指南免费把微信聊天记录导出成 PDF 和 Word 的完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表