openDialog
openDialog方法是FastCrud提供的一个纯js的弹窗API。
为什么要提供这个方法?
我们在使用el-dialog时,通常要在template里写<el-dialog>这样的代码, 有时这个弹窗逻辑可能只是一个局部方法里的,不希望弹窗相关的代码 蔓延的组件全局去。请看这个例子:
<template>
<div>
<el-button @click="check">核查</el-button>
...
<el-dialog v-model="dialogVisible" title="信息核查" width="80%">
<CheckPannel :propA="1" :propB="true" ...></CheckPannel>
<template #footer>
<el-button @click="checkOk">确认</el-button>
<el-button @click="checkCancel">取消</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import {ref} from "vue"
import {CheckPannel} from '...'
const dialogVisible = ref(false)
const check = () => {
dialogVisible.value = true
}
const checkOk = () => {
// 确认逻辑
}
const checkCancel = () => {
dialogVisible.value = false
// 取消逻辑
}
</script>上面这个简单的例子中, dialogVisible以及<el-dialog ..>标签其实都是check里的逻辑, 它们应该内聚在check 里才对, 但是为了定义弹窗, 我们不得不在template里写<el-dailog ...>标签, 然后为了控制弹窗显隐, 不得不在组件全局定义dialogVisible变量。 而事实上它们不应该污染组件全局。
FastCrud提供的openDialog方法可以让你直接以js驱动一个弹窗, 不需要定义el-dialog和visible 。上面这个例子使用FastCrud提供的openDialog改造后如下:
<template>
<div>
<el-button @click="check">核查</el-button>
...
</div>
</template>
<script setup>
import {util} from 'fast-crud-ui3'
import {CheckPannel} from '...'
const check = () => {
util.openDialog({
component: CheckPannel,
props: {
propA: 1,
propB: true
},
dialogProps: {
title: '信息核查',
width: '80%'
}
}).then(() => {
// 确认逻辑, 这里无需再控制弹窗显隐
}).catch(() => {
// 取消逻辑, 这里无需再控制弹窗显隐
})
}
</script>在上面这个例子中, 弹窗的逻辑都内聚在check内, 非常Nice!
但细心的朋友可能会发现: then和catch是怎么定义的呢?上面并没有定义dialog中的"确认"和"取消"按钮!
是的, FastCrud提供的这个openDialog方法,支持两种方式定义"确认"和"取消":
- 在自己的组件
CheckPannel中定义事件:ok和cancel, 按钮在CheckPanel中自行定义(形式不限, 也不一定就是按钮)。ok事件被触发后,走then,then可以有参数, 就是ok事件传递的参数,catch同理。 - 在
openDialog方法里通过参数定义按钮, 具体语法见下文。
openDialog参数
openDialog支持一个对象参数, 这个对象里支持三个配置项, 分别是:
- component: 要弹出的组件
- props: 要弹出的组件的prop配置
- dialogProps: 弹窗自身的prop配置
component和props非常好理解, 针对dialogProps, 下面具体说明下。
dialogProps
除了el-dialog自带的props外, 还额外支持四个配置项
| 属性 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| buttons | 定义dialog的#footer里的按钮 | Array<Object> | [] |
| okClose | 触发ok事件后,弹窗是否要关闭 | Boolean | true |
handleOk(1.5.12+) | ok事件的回调函数 | Function<any => void> | - |
handleCancel(1.5.12+) | cancel事件的回调函数 | Function<any => void> | - |
okClose: 很好理解, 有时ok事件触发后我们也不希望弹窗关闭, 而是希望用户主动去关弹窗, 就可以设置为false。handleOk: ok事件的回调函数。这和返回的promise.then作用几乎一致, 那为什么还要支持这个回调配置呢? 因为promise.then只能执行一次, 当okClose=false时, 往往可能需要ok回调函数能执行多次, 而then由于Promise机制无法满足。handleCancel: cancel事件的回调函数。同理, 作用和返回的promise.catch一致。
buttons
直接看例子:
import {CircleCheckFilled} from '@element-plus/icons-vue'
openDialog({
component: CheckPannel,
props: {
propA: 1,
propB: true
},
dialogProps: {
title: '信息核查',
width: '80%',
buttons: [
{
text: '确定',
type: 'primary',
size: 'default',
icon: CircleCheckFilled,
onClick: (component) => { // component就是传入的CheckPannel组件
// 这里可以利用component做更多事, 例如校验和获取数据并上抛—— 需要在CheckPannel里自行定义validate和getModel方法
if (!component.validate()) { // 校验
ElMessage.warning('校验不通过!')
return // 返回非Promise不会关闭弹窗
}
return Promise.resolve(component.getModel()) // 走then逻辑, 利用component获取数据并上抛
}
},
{
text: '取消',
onClick: (component) => {
return Promise.reject() // 走catch逻辑
}
}
]
}
}).then(model => {
// 确认逻辑
}).catch(() => {
// 取消逻辑
})如此, 弹窗实现就更内聚而合理, 你可以轻松的弹任何一个已有的component组件。
TIP
但如此也有一个显而易见的弊端, 就是弹出的内容必须独立到一个组件里。但换个方式理解,这恰恰有助于组件的合理抽取。 另外, openDialog是动态创建ElDialog节点, vue devtool可能无法识别解析弹窗组件(也许vue devtool后续版本会解决这个问题)