vue封装el-form实现高度配置化

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、效果:

 

Vue3中,`el-form`是Element UI提供的表单组件,为了提高代码复用性和灵活性,我们可以对其进行二次封装。二次封装通常是将原生组件抽取成自定义的Vue组件,并提供更简洁、易用的API。 步骤大致如下: 1. **导入基础组件**:首先需要在项目中安装Element UI库,并引入`ElForm`组件。 ```js import { ElForm } from 'element-plus'; ``` 2. **创建组件模板**:创建一个新的Vue组件文件,如`CustomForm.vue`,并设置基本结构,包括`form`属性用于接收外部传入的数据。 ```html <template> <el-form ref="customForm" :model="form" :rules="rules"> <!-- 根据实际需求添加表单元素 --> </el-form> </template> ``` 3. **数据绑定和生命周期钩子**:在组件内部,通过`ref`获取到`el-form`实例,处理表单提交、验证等操作。同时可以添加`watch`监听数据变,以及`mounted`等生命周期钩子。 ```js <script> export default { props: { form: { type: Object, required: true, }, rules: { type: Object, // ... 规则配置 }, }, setup(props) { const customFormRef = ref(null); onMounted(() => { customFormRef.value.validate(); }); // 添加事件处理器 watch( () => props.form, (newData) => { customFormRef.value.setFieldsValue(newData); }, { deep: true } ); return { customFormRef, }; }, }; </script> ``` 4. **对外暴露API**:提供一些方法供外部使用,比如提交表单、校验表单等。 ```js // 在methods中定义方法 export default { methods: { handleSubmit() { this.customFormRef.value.submit(); }, handleValidate() { this.customFormRef.value.validate(); }, }, }; ``` 5. **使用组件**:在其他地方引用并使用自定义的`CustomForm`组件,传递所需的数据和规则。 ```vue <template> <CustomForm :form="myFormData" :rules="validationRules" @submit="handleSubmit" ></CustomForm> </template> <script> import CustomForm from '@/components/Common/CustomForm'; export default { components: { CustomForm, }, data() { return { myFormData: {}, validationRules: {}, }; }, methods: { // 使用自定义方法 }, }; </script> ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值