1、封装 Form.vue:

<template>

  <el-form 
    v-bind="$attrs" 
    v-on="$listeners" 
    :model="data"
    ref="form"
    @submit.native.prevent>

    <el-form-item 
      v-for="(item,index) in items" 
      :key="index"
      v-bind="getFormItemBind(item)"
      v-on="getFormItemOn(item)">

      <template v-if="$scopedSlots[item.prop]">
        <slot 
          :name='item.prop' 
          :item='item' 
          :data="data" />
      </template>

      <component
        v-else
        v-model="data[item.prop]"
        v-bind="getBind(item)"
        v-on="getOn(item)"
        :is="item.type"
      />

    </el-form-item>
    
    <!-- 拓展插槽,适合添加查询新增按钮 -->
    <slot
      :items="items" 
      :data="data" />

  </el-form>
</template>
<script>
import * as _ from 'lodash'
let isObject = data => Object.prototype.toString.call(data) === '[object Object]'
let isFunction = data => Object.prototype.toString.call(data) === '[object Function]'

let config = {

  getFormItemBind:item => ({
    rules: (item.required && item.label) ? { required: true, message: "请输入"+item.label } : null,
    ...item,
    label: item?.label ? item?.label+':' : '',
  }),
  getDefBind(item) {
    return (
      {
        'el-input': {
          placeholder: "请输入" + item.label,
        },
        'el-date-picker': {
          placeholder: "请选择" + item.label,
          valueFormat: "yyyy-MM-dd HH:mm:ss",
          type: "datetime",
        },
        'el-input-number': {
          placeholder: "请输入" + item.label,
        },
        'el-select': {
          placeholder: "请选择" + item.label,
        },
        'el-switch': {
          activeValue: true,
          inactiveValue: false,
          activeText: "是",
          inactiveText: "否",
        },
      }[item.type] || {}
    );
  },
}
export default{
  config,
  props:{
    value:Object,
    items:Array,
  },
  computed:{
    data:{
      get(){
        return this.value
      },
      set(value){
        this.$emit('input',value)
      }
    }
  },
  methods:{
    //----------普通方法-----------
    resetFields(){
      this.$refs.form.resetFields()
    },
    clearValidate(){
      this.$refs.form.clearValidate()
    },
    validate(callback){
      this.$refs.form.validate(callback)
    },
    getFormItemBind(item){
      return config.getFormItemBind(item)
    },
    getFormItemOn(item){
      return isObject(item.formItemOn) 
            ? item.formItemOn 
            : isFunction(item.formItemOn)
              ? item.formItemOn(item, this.value)
              : {} 
    },
    getBind(item) {
      let defBind = config.getDefBind(item),
        bind = isObject(item.bind)
          ? item.bind
          : isFunction(item.bind)
          ? item.bind(this.value, item, this.row)
          : {};
      return _.merge(defBind, bind);
    },
    getOn(item) {
      return isObject(item.on)
        ? item.on
        : isFunction(item.on)
        ? item.on(this.value, item, this.row)
        : {};
    },

    //----------点击事件-----------

    //----------接口方法-----------
  }
}
</script>
<style lang="scss">
</style>

2、用法:

<template>
  <div>
    <EForm v-model="data" :items="items" label-width="100px">

      <EBtn @click="_c_look">提交</EBtn>

    </EForm>

  </div>
</template>

<script>
export default {
  data() {
    let _this = this
    return {
      data:{
        file:[{
          name: "埃菲尔铁塔.png",
          url: "/data/file/2022/05/26/117608f0-3d73-42ff-8df0-353a8ca2b5fc.png"
        }],
        images:[{
          name: "埃菲尔铁塔.png",
          url: "/data/file/2022/05/26/117608f0-3d73-42ff-8df0-353a8ca2b5fc.png"
        }],
      },
      items: [
        {
          prop: "name",
          label: "案例名称",
          type: "el-input",
          required: true,
        },
        {
          prop: "start_time",
          label: "发生时间",
          type: "el-date-picker",
          bind: {
            type: "datetime",
            placeholder: "请选择发生时间",
          },
        },
        {
          prop: "text",
          label: "描述",
          type: "el-input",
          bind: {
            type: "textarea",
            autosize: { minRows: 2 },
          },
        },
        {
          prop: 'type',
          label: '类型',
          type: 'ESelect',    // 这是自己封装的组件名称
          bind:{
            valueKey: 'id',
            list: _this.$store.state.typeList,
            optionBind:val => ({
              label: val.name + '自定义',
              value: val
            })
          }
        },
        {
          prop: 'file',
          label: '文件',
          type: 'EUploadFile',    // 这是自己封装的组件名称
          bind:{
            action: '/api/api/v1/file/upload',
            getFile(res){
              return {
                name: res.file_path[0].originname,
                url: res.file_path[0].storagepath,
              }
            },
          }
        },
        {
          prop: 'images',
          label: '图片',
          type: 'EUploadPicture',
          bind:{
            action: '/api/api/v1/file/upload',
            getFile(res){
              return {
                name: res.file_path[0].originname,
                url: res.file_path[0].storagepath,
              }
            },
          }
        },
        {
          prop: 'switch',
          label: '开关',
          type: 'el-switch'
        }
      ],
    }
  },
  mounted() {},
  watch:{
    '$store.state.typeList'(n, o){
      this.items[3].bind.list = n
    }
  },
  methods: {
    _c_look(){
      console.log(this.data);
    }
  },
};
</script>

<style></style>

3、效果:

 

Logo

前往低代码交流专区

更多推荐