弹窗封装、数据视图分开。

132 阅读1分钟

前提:平常工作中,总会用到大量的弹窗,这时我们对弹窗进行封装一下,总是好用的。

一、弹窗封装

<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 处理业务逻辑,目录截图如下

image.png

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>