业务场景:
弹窗一般用于数据编辑、数据选择和动作确认,归纳而言就是作为某个流程的中间环节
已知实现方案和优劣:
1.(暂定)把弹窗及内容封装为一个组件,该组件暴露一个返回 promise 的 open 方法来打开弹窗。代码如下:
- 父组件中使用封装好的弹窗组件 CustomersDetail.vue
<template>
<div>
<el-button @click="addCustomers">新增客户</el-button>
<CustomersDetail ref="customersDetail"></CustomersDetail>
</div>
</template>
<script>
import { defineComponent, ref } from '@vue/composition-api'
import CustomersDetail from './CustomersDetail.vue'
export default defineComponent({
components: { CustomersDetail },
setup() {
const customersDetail = ref(null)
const addCustomers = async () => {
const customersData = await customersDetail.value.open()
// ...doSome
}
return {
addCustomers,
customersDetail
}
}
})
</script>
- 弹窗组件 CustomersDetail.vue 中使用 useDialog
<!-- CustomersDetail.vue -->
<template>
<el-dialog title="新增客户" :visible="visible" v-loading="loading" append-to-body id="app" @close="cancel" center>
<el-form :model="formData">
<el-col span="8">
<el-form-item label="客户姓名:">
<el-input v-model="formData.customerName"></el-input>
</el-form-item>
</el-col>
<el-col span="8">
<el-form-item label="客户电话:">
<el-input v-model="formData.customerPhone"></el-input>
</el-form-item>
</el-col>
<el-col span="8">
<el-form-item label="客户邮箱:">
<el-input v-model="formData.customerEmail"></el-input>
</el-form-item>
</el-col>
</el-form>
<span slot="footer">
<el-button type="primary" @click="confirm(formData)">确认</el-button>
<el-button type="primary" @click="cancel">取消</el-button>
</span>
</el-dialog>
</template>
<script>
import { defineComponent, reactive } from '@vue/composition-api'
import { useDialog } from './useDialog'
function initFormData() {
return {
customerName: '',
customerPhone: '',
customerEmail: ''
}
}
export default defineComponent({
setup() {
const { visible, openFactory, loading, confirm, cancel } = useDialog()
const formData = reactive(initFormData())
const open = openFactory((params) => {
Object.assign(formData, initFormData(), params)
})
return {
confirm,
visible,
loading,
cancel,
formData,
open
}
}
})
</script>
- 封装弹窗公共逻辑为 useDialog
export const useDialog = () => {
const visible = ref(false)
const openFactory = (init) => {
return (params) => {
return new Promise(async (resolve, reject) => {
visible.value = true
loading.value = true
await init(params)
loading.value = false
resolveFun = resolve
})
}
}
let resolveFun
const loading = ref(false)
const confirm = (dialogData) => {
visible.value = false
resolveFun(dialogData)
}
const cancel = () => {
visible.value = false
resolveFun(null)
}
return {
visible,
openFactory,
loading,
confirm,
cancel
}
}
2.采用传入 visible 打开弹窗,监听 confirm 和 cancel 事件获取用户操作的结果
- 缺点:
- 在父组件需要定义并操作 visible 状态
- 打开弹窗的动作和后续的行为位于两个独立函数中,不利于业务理解