手把手教你以最简单的方式封装 Vue3 模态(Modal) 类组件

反馈型组件,是前端经常涉及的组件,它们允许向用户提供提醒、提供更多选项或添加额外信息,而不会弄乱主要内容。

在 Vue 中 Modal 类组件使用通常分为两种方式

  • 组件声明模式(declarative

优点:定制化程度高、限制低,可以最大程度的发挥主管设计想法

缺点:复用性差、使用频繁时需要定义多份 { show, onOk, onClose } 代码,代码冗余。

  • 函数调用模式(imperative
Modal.confirm({
    title: '...',
    contnet: '...'
})
    .then(() => {/* ok */})
    .catch(() => { /* close */})

优点:数据独立与页面独立、复用性、通用性强、业务代码流程易懂、无法继承上下文

缺点:涉及到定制化将很难处理,往往需要编写 template 字符串 / jsx 代码

弹出层组件涉及思路

说了那么多,也该进入主题了。在前端发展至今为止,这类组件的封装已经有了广泛的累积,

其中函数调用(imperative)无非就是利用了 vuerender 能力,将一个组件直接渲染至 html 当中,但实际做起来还是相当麻烦,需要处理 render销毁的时机,还需要想办法将处理函数传递给组件自身,且无法和组件声明模式相结合使用。

并且考虑在实际项目开发当中,我们可能并不会考虑重头实现一个 dialog 组件,而是使用第三方组件库自带的去魔改,实际上就会遇到各种各样的问题。

综上考虑成本还是过高,但还是有可解决的思路,所以我们明确以下几点要求:

  • 组件可支持组件声明、函数调用两种模式(declarative and imperative
  • 定制化能力强、开发成本低,以最简单的方式制作模态类组件
  • 使用现有组件库(如 element-plus)集成和定制化功能
  • 支持组件继承全局应用上下文

那么基于上面几点,普通原始(vue render / tempalte)的方式封装就不能满足我们的需求,我们需要一个趁手的工具帮我们做这些事情。

笔者将这套逻辑抽离了出来,形成了一套完整的 Vue3 弹出层解决方案 unoverlay-vue,它可以满足我们上述的所有要求。

关于实现基层原理方面,本文不作过多展示,可以查看笔者以往文章 # Vue3 模态框封装方案

⚙️ Install

pnpm add unoverlay-vue
# Or Yarn
yarn add unoverlay-vue

在 main.js 中全局安装可以使所有弹出层继承上下文

// main.js
import { createApp } from 'vue'
import unoverlay from 'unoverlay-vue'
import App from './App.vue'

const app = createApp(App)
app.use(unoverlay)
app.mount('#app')

实现基础的 Modal 功能

定义 Model 组件,这里以最简案例实现,不包含动画逻辑(可以使用 实现)

你可以大胆地发挥你的想象力



创建函数调用回调(imperative), 在 Javascript / Typescript 中调用

import { transformOverlay } from 'unoverlay-vue'
import Model from './Model.vue'

// 转换函数调用模式(imperative)
const ModelCallbck = transformOverlay(Model)
// 调用并获取 confirm 回调的值
const value = await ModelCallbck({ title: 'callbackOverlay' })
// value === "callbackOverlay:confirmed"

或者任意地方直接调起组件

import { useOverlayCall } from 'unoverlay-vue'
import Model from './Model.vue'

const value = await useOverlayCall(Model, {
  props: { title: 'useOverlay' }
})
// value === "useOverlay:confirmed"

或者在 template 中以组件声明模式(declarative)使用