Vue3中如何用h函数封装命令式Dialog组件

发布时间:2026/9/9 21:02:21
Vue3中如何用h函数封装命令式Dialog组件 做了这么多年 Vue 项目我越来越觉得“弹窗”是前端里最应该被抽成命令式的组件。平时用模板语法加 v-model 写 dialog 写多了每个页面里都要维护一个 visible 变量弹窗一多代码全是重复的开关逻辑。今天这篇文章我用 Vue 的 h 函数把 dialog 组件封装成命令式调用让你在业务代码里直接通过一个函数弹出一个对话框不用再写一行 v-model。这篇内容适合用过 Vue3、写过几个组件、但对 createVNode/render 还停留在“看过没用过”阶段的人。我会从 h 函数的原理讲起一步步搭出完整的封装层最后把真实项目中踩过的坑也一并列出来照着抄就行。1. 为什么非要把 Dialog 改成命令式调用1.1 模板式写法到底麻烦在哪先给一个最常见的场景列表页删除确认。你大概率是这样写的template el-dialog v-modeldialogVisible title删除确认 p确定要删除这条数据吗/p template #footer el-button clickdialogVisible false取消/el-button el-button typedanger clickhandleDelete删除/el-button /template /el-dialog /template script setup import { ref } from vue; const dialogVisible ref(false); const currentRow ref(null); function openDeleteConfirm(row) { currentRow.value row; dialogVisible.value true; } async function handleDelete() { await deleteApi(currentRow.value.id); dialogVisible.value false; // 刷新列表 } /script单看一个弹窗好像还行。但只要页面里再塞上“新增表单弹窗”、“编辑弹窗”、“批量删除确认”、“审核结果弹窗”问题就全部暴露出来了每个弹窗都要单独维护一个 visible、都要写关闭回调、都要围绕当前弹窗搞一堆状态。要是哪天产品经理说“所有确认框统一改成某种风格”你就要逐个页面找这些模板和事件改到怀疑人生。更麻烦的是模板式弹窗把“交互流程”硬生生拆成了“打开”和“处理”两段。打开靠修改 visible处理靠监听事件中间隔着一层模板读代码的时候脑子里得来回跳。对于确认框这种一问一答的交互这种拆分属于过度设计。1.2 命令式调用能省掉哪些事儿对比一下同样的删除确认用命令式写法是什么样const ok await openConfirm({ title: 删除确认, content: 确定要删除这条数据吗, confirmText: 删除 }); if (ok) { await deleteApi(id); refreshList(); }这段代码没有任何 v-model不需要额外声明状态也不需要嵌套在模板里。弹窗的挂载、显隐、卸载都被封装层处理了业务代码只需要关心“用户点没点确认”。这就是命令式调用的价值把一次交互行为变成一个可等待的函数调用逻辑上非常接近“你问用户一个问题拿到一个答案”。尤其是像删除这种高风险操作弹窗的确认结果直接决定后续流程命令式写法能让你把这一段流程按顺序读下来读代码的成本也低了不少。对于中后台项目这种能力的收益尤其明显。表格里的操作列、路由守卫里的未保存提示、表单提交前的二次确认……全都是弹窗高发场景。用命令式封装之后你的业务代码里没有弹窗的影子只有清楚的逻辑流程。1.3 不是所有场景都适合命令式这里要说句公道话。命令式调用适合“短暂、低频、结果明确”的交互比如确认框、结果反馈、轻量表单。如果弹窗内容是一个复杂的表单需要和页面里的其他状态联动或者需要通过 slot 传入大量自定义内容硬套命令式反而会写出一堆别扭的配置。此时老老实实用模板加 v-model配合子组件封装才是更稳的选择。我自己对团队的建议是全局确认类弹窗、消息提醒类弹窗尽量命令式页面内部低频使用的表单弹窗保持模板写法。两者共存不冲突。命令式不是银弹但它能精准解决一大类重复劳动。2. 核心原理h 函数与运行时渲染到底做了什么2.1 h 函数到底是什么在 Vue3 里h 函数负责把“你想要渲染的东西”变成一个 VNode。你可以把 VNode 理解成一个“虚拟节点描述对象”它既不是真实 DOM也不是组件实例只是用 JavaScript 对象描述“这里该渲染什么”import { h } from vue; const vnode h(div, { class: box }, hello);上面这行代码返回的是一个普通的 JavaScript 对象它描述的是“这里要渲染一个 divclass 是 box文本内容是 hello”。真正把 VNode 变成浏览器里的 DOM要交给后面的 render 函数。对于组件我们也可以创建组件 VNodeconst vnode h(MyDialog, { title: 提示 });这里传给 h 的第一个参数不是字符串而是组件对象。Vue 在创建 VNode 时会保留对这个组件的引用后续 patch 阶段会负责创建组件实例。有一点要注意在 Vue3 中 h 其实是 createVNode 的封装别名两者的返回值基本一致。h 主要提供了一些便利的归一化处理比如自动把 children 处理成数组、对 props 做浅层处理等等。平时写业务代码用 h 就够了只有阅读框架源码或封装底层工具时才需要直接接触 createVNode。对我们这次的封装来说h 和 createVNode 哪个都行但为了跟 Vue 内部 API 对齐我在下面统一用它俩的组合。2.2 render 函数把 VNode 变成真实 DOM有了 VNode下一步就是渲染。Vue3 提供了 render 函数import { render } from vue; render(vnode, document.getElementById(app));render(vnode, container) 的逻辑是如果 container 里已经有内容了它会做对比更新patch如果这个 vnode 是全新的就直接创建 DOM 并插入。如果传入的 vnode 是 null它会卸载 container 里已有的内容。这个“传入 null 就卸载”的特性正是我们做命令式弹窗的核心。封装层要销毁一个弹窗只需要执行render(null, container)一行。另外有一个容易被新手忽略的点render 的第一个参数可以传 null也可以传新的 VNode 来做整体替换。Vue 在内部的 patch 逻辑很复杂有 diff、有 key 比对但在命令式弹窗这个场景我们一般都用不到复杂 diff因为整个弹窗从创建到销毁就是完整的生命周期创建挂载、显示、销毁。2.3 命令式组件的挂载机制现在把 h 和 render 串起来就得到命令式组件的基本骨架import { createVNode, render } from vue; import MyDialog from ./MyDialog.vue; export function showDialog(options) { const container document.createElement(div); const vnode createVNode(MyDialog, options); render(vnode, container); document.body.appendChild(container); // 销毁 render(null, container); container.remove(); }过程是先创建一个空 div 作为容器把组件 VNode 渲染进去再把整个容器追加到 body。等到需要关闭时先 render(null, container) 清空容器内部的组件再把容器从 body 移除。注意“先清除再移除”这个顺序很多坑都是从这里来的后面我会专门讲。用生活化的类比h 函数相当于“下订单”采购清单里写了要什么组件、传什么参数render 在 container 里“开箱组装”组件变成真实 DOMrender(null, container) 相当于“退货清场”把现场还原。一个空 div 就是一个临时的“柜台”摆到 body 上用完撤走。这个机制不仅是弹窗专用toast、message、popover、drawer 这类轻交互组件底层基本都是这个套路。理解了这一套你会发现 Vue 的运行时渲染没有想象中那么神秘。3. 实战封装用 h 函数写一个完整的命令式 Dialog3.1 第一步Dialog 内容组件只负责展示命令式封装不需要把 Dialog 组件本身写得很复杂它只需要

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询