# 函数化弹窗组件
创新永远属于懒人!
参照:MessageBox - element-ui (opens new window)
第一次用到 element-ui 的弹窗时,惊为天人,因为之前用 Vuetify 的时候都是自己手撸完整的弹窗和逻辑,从没想过还能有 this.$confirm()
这么简便的调用方式。
但 Vue 的生命周期和脱离纯 .vue 用 js 写 Vue 一直是我的弱项,此前也尝试过将 Vuetify 的弹窗封装成这样,可惜最后以失败告终,不得不借用别人写的 vuetify-dialog (opens new window),而且还看不懂源码......
这一次,我直接从 element-ui 的源码入手,花了大概两个小时,总算是搞定了函数化弹窗组件的实现~
# 调用方式
我们的目标是模仿 element-ui,通过 MessageBox.confirm('弹窗文字')
函数式调用弹窗组件
import MessageBox from 'MessageBox.js'
Vue.extend({
methods: {
onClick() {
MessageBox.confirm('是否确认').then(res => {}).catch(() => {})
}
}
})
# 实现方式
- 创建 MessageBox.vue 和 MessageBox.js
MessageBox.vue 用来编写弹窗组件的 HTML 结构和样式,还有必需的数据和逻辑。
MessageBox.js 用来进行导出的包装,同时也要负责 Vue 组件的创建、挂载和修改。
- 设计(搞清楚)从调用函数,到弹窗显示,到弹窗确认的流程
首先,MessageBox.confirm() 调用 MessageBox 函数。
MessageBox.confirm = (text) => {
return MessageBox({
text
})
}
然后,MessageBox 函数返回一个 Promise 对象(所以我们可以在调用后接 then 和 catch 来处理结果)。
const MessageBox = function (options) {
return new Promise((resolve, reject) => {
show(options, resolve, reject)
})
}
show 函数负责创建弹窗组件的 Vue 实例,将其挂载到 DOM 并根据传入的 options 修改其数据。
show 保存了这个 Promise 的 resolve 和 reject,以允许 Vue 组件通过回调向 Promise 传数据。
function show (options, resolve, reject) {
if (!instance) {
init()
}
// action 用于标明弹窗的动作类型,比如 confirm-提交/cancel-取消
instance.action = ''
// text 为自定义的弹窗提示文字
instance.text = options.text
// callback 提供给组件调用以实现向 Promise 传数据
instance.callback = (action) => {
if (action === 'confirm') {
// inputVal 是从组件中传来的数据
resolve(instance.inputVal)
} else {
reject()
}
}
document.body.appendChild(instance.$el)
Vue.nextTick(() => {
// show 用于控制 MessageBox 组件的显隐
instance.show = true
})
}
这里的 instance 和 init() 就是一个简单的单例模式,保证全局只有一个 Vue 组件。
let instance
function init () {
instance = new MessageBoxConstructor({
el: document.createElement('div')
})
}
以上都是 MessageBox.js 中的内容,下面让我们来看 MessageBox.vue 如何与 MessageBox.js 交互。
正如介绍 show 时所说,MessageBox.vue 通过调用 callback 与 MessageBox.js 通讯。
Vue.extend({
methods: {
doClose () {
this.show = false
setTimeout(() => {
if (this.callback) {
this.callback(this.action, this)
}
})
}
}
})
而 doClose 在动作按钮被点击改变 action 时被调用(这里的逻辑主要看具体场景和个人需求)。
Vue.extend({
methods: {
handleAction (action) {
this.action = action
this.doClose()
}
}
})
经过这一整个流程,我们就能实现:通过调用函数的方式显示弹窗 => 点击弹窗的取消/提交使弹窗关闭 => 弹窗中的数据通过 Promise 传来被我们的业务逻辑处理。
今天这个篇幅好像有些过长,完整的代码和使用请大家在 pass-no-fail (opens new window) 里找吧~
← 初试 electron 归来 →