前提:平常工作中,总会用到大量的弹窗,这时我们对弹窗进行封装一下,总是好用的。
一、弹窗封装
<template>
<zk-modal
v-model="visible"
:title="modalObj.title"
v-bind="$attrs"
:width="width"
:mask-closable="false"
v-on="$listeners">
<div slot="title">
{{ modalObj.title }}
</div>
<div class="dialog-content">
// 弹窗内其他内容插槽配置
<slot name="extraInfo"></slot>
<zk-form
id="modalForm"
ref="modalForm"
label-width="100px"
label-suffix=":"
:model="modalForm"
:rules="modalObj.rules">
<zk-row :gutter="[8, 4]">
<zk-col
v-for="item in modalObj.config"
:key="item.key"
:span="12">
<zk-form-item
:label="item.bindingConfig.label || ''"
:prop="item.model">
<zk-select
v-if="item.type === 'select'"
v-model="modalForm[item.model]"
placeholder="请选择"
:size="item.bindingConfig.size"
:disabled="item.bindingConfig.disabled"
:multiple="item.bindingConfig.multiple"
:all-select="item.bindingConfig.multiple"
clearable
filterable
:collapse-tags="item.bindingConfig.multiple"
:multiple-limit="item.bindingConfig.multipleLimit">
<zk-option
v-for="opt in item.options"
:key="opt.value"
:label="opt.label"
:value="opt.value"
:disabled="opt.disabled || false" />
</zk-select>
<zk-input
v-if="item.type === 'input'"
v-model="modalForm[item.model]"
:disabled="item.bindingConfig.disabled"
placeholder="请输入"
size="small"
clearable />
<zk-input
v-if="item.type === 'textarea'"
:disabled="item.bindingConfig.disabled"
v-model="modalForm[item.model]"
placeholder="请输入"
type="textarea"
size="small"
clearable />
<zk-date-picker
v-if="item.type === 'datePicker'"
v-model="modalForm[item.model]"
:disabled="item.bindingConfig.disabled"
type="daterange"
clearable />
<zk-date-picker
v-if="item.type === 'date'"
v-model="modalForm[item.model]"
:disabled="item.bindingConfig.disabled"
:picker-options="item.bindingConfig.pickerOptions"
clearable
type="date" />
<zk-date-picker
v-if="item.type === 'datetime'"
v-model="modalForm[item.model]"
:disabled="item.bindingConfig.disabled"
clearable
type="datetime"
:picker-options="item.bindingConfig.pickerOptions" />
<zk-date-picker
v-if="item.type === 'datetimerange'"
v-model="modalForm[item.model]"
:disabled="item.bindingConfig.disabled"
clearable
type="datetimerange"
:picker-options="item.bindingConfig.pickerOptions" />
<zk-radio-group v-if="item.type === 'radio'" v-model="modalForm[item.model]">
<zk-radio
v-for="opt in item.options"
:key="opt.value"
:label="opt.value"
:value="opt.value">
{{ opt.label }}
</zk-radio>
</zk-radio-group>
</zk-form-item>
</zk-col>
</zk-row>
</zk-form>
<slot name="footerInfo"></slot>
</div>
<div
slot="footer"
class="flex-end">
<slot name="footer">
<zk-button @click="visible = false">
{{ cancelText }}
</zk-button>
<zk-button
type="primary"
:loading="loading"
@click="confirm">
{{ confirmText }}
</zk-button>
</slot>
</div>
</zk-modal>
</template>
<script>
export default {
props: {
// 确定按钮文案
confirmText: {
type: String,
default: '确 定'
},
// 取消按钮文案
cancelText: {
type: String,
default: '取 消'
},
// 弹窗标题
title: {
type: String,
default: '标题'
},
// 弹窗的一些配置,比如表单相关、校验都可以放在这里
modalObj: {
type: Object,
default: () => {}
},
// 弹窗宽度
width: {
type: String,
default:'800px'
}
},
data() {
return {
loading: false,//确定按钮 loading 状态
visible: false,//是否显示弹窗
modalForm: {},// 当前弹窗表单的配置
};
},
watch:{
visible(val) {
if (!val) {
this.loading = false;
this.$refs.modalForm.resetFields();
}
}
},
mounted() {
// this.initForm();
},
methods: {
// 初始化表单
initForm() {
const copyData = {};
this.modalObj.config && this.modalObj.config.forEach((item) => {
// 把配置过来的数据初始化给表单 moddalForm
copyData[item.model] = item.value;
});
this.modalForm = copyData;
},
// 提交按钮点击事件
confirm() {
this.$refs.modalForm.validate((valid, validRes) => {
if (valid) {
this.loading = true;
this.$emit('submitModal', this.modalForm);
} else {
console.error('校验错误', validRes);
}
});
},
}
};
</script>
二、全局注册封装好的弹窗组件
在 main.js 中引入
import CustomModal from '@/components/CustomModal/index';
Vue.component('CustomModal', CustomModal);
三、目录文件
我们把页面的数据和视图分开放两个文件,如下 config.js 放一些不太会变的数据配置,index.vue 处理业务逻辑,目录截图如下
1. config.js 文件
export const modalForm = {
// 修改
updateForm: {
title: '修改采购订单',
config: [
{
type: 'select',//表单类型
model: 'productFactoryCode',// 字段名
value: '',
bindingConfig: {
label: '工厂',
disabled: false,
},
options: [], // 选择框下拉数据
},
{
type: 'textarea',
model: 'orderRemark',
value: '',
bindingConfig: {
label: '备注'
}
}
],
// 表单校验规则
rules: {
productFactoryCode: [
{ required: true, message: '请选择工厂', trigger: 'change' }
],
priorityLevel: [
{ required: true, message: '请选择优先级', trigger: 'change' }
],
}
},
};
2. index.vue 页面
<template>
<!-- 修改弹窗-->
<CustomModal ref="CustomModal" :modal-obj="modalForm.updateForm" @submitModal="submitModal">
// 弹窗内插槽
<div slot="extraInfo">
取消后,PO单无法恢复是否确认?
</div>
</CustomModal>
</template>
<script>
import {modalForm } from './config';
export default {
data() {
return {
modalForm,
modalObj: {},// 弹窗的配置对象,例如:弹窗标题,校验规则
rowObj: {}
};
},
methods: {
async initData() {
const { data } = await window.apisMap.common.queryAllFactory();
this.factoryData = data;
this.modalForm.updateForm.config.find(ele => ele.model === 'productFactoryCode').options = window.utilsMap.changeKeys(data, 'factoryCode', 'factoryName');
},
submitModal(query) {
this.type === 'cancel' ? this.cancelSubmit(query) : this.updateSubmit(query);
},
// 编辑订单
editOrderReady(row) {
this.modalForm.updateForm.title = '修改采购订单';
this.$refs.CustomModal.initForm();
this.$refs.CustomModal.visible = true;
this.rowObj = row;
},
// 修改: 返回的data就是表单的数据
async updateSubmit(data) {
const params = {
...data,
};
const res = await window.apisMap.purchaseOrder.updateOrder( params );
if (res.code === 200) {
this.$refs.CustomModal.visible = false;
this.$message({ type: 'success', duration: 4000, message: '采购订单信息修改成功' });
} else {
this.$refs.CustomModal.loading = false;
}
},
},
};
</script>