这是在前一次封装的基础上加以完善,上一次的简单封装,可以看下这里vue+element-ui form表单的简单封装
页面大致如下:
在这里插入图片描述
直接上代码~
Form组件封装:EditForm.vue
表单字段rules校验,render,slot等使用

<template>
  <el-form
    ref="form"
    v-bind="computedConfig"
    :rules="rules"
    :model="data"
  >
    <el-row>
      <el-col
        v-for="(item, index) in computedItems"
        :key="getItemKey(item, index)"
        :md="item.md"
        :sm="item.sm"
      >
        <el-form-item :label="item.label + ':'" :prop="item.prop">
          <render-content
            slot="label"
            v-if="item.labelRender"
            :render="item.labelRender"
            :data="item"
          ></render-content>
          <slot :name="item.slot" v-bind="{ item }">
            <component
              v-if="item.component"
              :ref="item.ref || `cp-${item.prop}`"
              :is="item.component"
              :data="data"
              v-model="data[item.prop]"
              v-bind="item.props"
              v-on="item.listeners"
              />
            <span v-else>{{data[item.prop]}}</span>
          </slot>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>
<script>
const defaultConfig = {
  labelWidth: '120px'
}
// 表单字段格式化
const RenderContent = {
  props: {
    render: Function,
    formatter: Function, // 格式化数据
    data: Object,
    prop: String
  },
  render (h) {
    if (this.render) {
      return this.render(h, this.data)
    }
    let value = this.data[this.prop]
    if (this.formatter) {
      value = this.formatter(value, this.data)
    }
    return <span>{value}</span>
  }
}
// element UI 组件
const alias = {
  input: {
    component: 'el-input',
    props: {}
  },
  textarea: {
    component: 'el-input',
    props: {
      type: 'textarea'
    }
  },
  radio: {
    component: 'el-radio',
    props: {}
  },
  label: {
    component: 'render-content',
    props: {}
  },
  select: {
    component: 'el-select',
    props: {}
  },
  datePicker: {
    component: 'el-date-picker',
    props: {
      style: {
        width: '100%'
      },
      "value-format": 'timestamp'
    }
  }
}

export default {
  components: {
    RenderContent
  },
  props: {
    formConfig: Object,
    formItems: Array,
    data: Object
  },
  computed: {
    computedConfig () {
      return {
        ...defaultConfig,
        ...this.formConfig
      }
    },
    computedItems () {
      const itemResult = []
      for (const item of this.formItems) {
        // 剩余参数语法允许我们将一个不定数量的参数表示为一个数组。theArgs
        let {component, showIf, prop, props, ...theArgs} = item
        if (typeof showIf === 'function' && !showIf(this.data)) {
          continue
        }
        if (typeof props === 'function') {
          props = props(this.data)
        }
        if (component === 'label') {
          props = {
            ...props,
            data: this.data,
            prop
          }
        }
        if (alias[component]) {
          props = {
            ...alias[component].props,
            ...props
          }
          component = alias[component].component
        }
        itemResult.push({
          component,
          prop,
          props,
          ...theArgs
        })
      }
      return itemResult
    },
    rules () {
      let rules = this.computedItems.reduce((total, item) => {
        if (item.rules) {
          let rules = item.rules
          if (typeof rules === 'function') {
            rules = rules(this.data)
          }
          total[item.prop] = rules
        }
        return total
      }, {})
      return rules
    }
  },
  methods: {
    getItemKey (item, index) {
      return `${item.prop}-${index}`
    },
    validate () {
      return new Promise(resolve => {
        this.$refs.form.validate(resolve)
      })
    },
    clearValidate (props) { // 清空校验
      this.$refs.form.clearValidate(props)
    }
  }
}
</script>

EditForm组件的使用:

<template>
  <div>
    <div style="width: 800px;margin: 0 auto;">
      <edit-form
        ref="editForm"
        :form-items="formItems"
        :form-config="formConfig"
        :data="form"
      >
        <div slot="actRange2">
          <el-select style="width: 100%" v-model="form.actRange2" placeholder="请选择活动区域">
            <el-option label="区域一" value="shanghai"></el-option>
            <el-option label="区域二" value="beijing"></el-option>
          </el-select>
        </div>
      </edit-form>
      <el-button @click="submit">submit</el-button>
    </div>
  </div>
</template>
 <script>
 import EditForm from './EditForm'
    export default {
      components: {
        EditForm
      },
      data() {
        return {
          form: {
            date: '',
            name: '',
            address: 'default address',
            actRange: '',
            actRange2: ''
          },
          formConfig: {
            labelWidth: '120px'
          },
          formItems: [
            {
              label: '日期',
              prop: 'date',
              component: 'datePicker',
              labelRender: () => {
                return (
                  <span>
                    <el-tooltip effect="light" placement="left">
                      <template slot="content">
                        请选择日期
                      </template>
                      <i class="label-tip-icon el-icon el-icon-question"></i>
                    </el-tooltip>
                    日期:
                  </span>
                )
              },
              md: 12,
              sm: 12,
              rules: [
                { required: true, trigger: 'change', message: '请选择日期' }
              ]
            },
            {
              label: '姓名',
              prop: 'name',
              component: 'input',
              props: {
                placeholder: 'please enter name'
              },
              md: 12,
              sm: 12,
              rules: form => {
                return form.date
                  ? [{ required: true, trigger: 'blur', message: '请输入姓名' }]
                  : []
              }
            },
            {
              label: '地址',
              prop: 'address',
              component: 'input',
              props: {
                disabled: true,
                placeholder: 'please enter address'
              }
            },
            {
              label: '活动',
              prop: 'activity',
              component: 'input',
              showIf: () => false,
              props: {
                disabled: true,
                placeholder: 'please enter activity'
              }
            },
            {
              label: '范围1',
              prop: 'actRange1',
              component: 'select',
              showIf: () => true,
              props: {
                style: {
                  width: '100%'
                },
                disabled: false,
                placeholder: 'please enter activity'
              }
            },
            {
              label: '范围2',
              prop: 'actRange2',
              showIf: () => true,
              slot: 'actRange2'
            }
          ]
        }
      },
      methods: {
        async submit () {
          const valid = await this.$refs.editForm.validate()
          if (!valid) {
            return
          }
          console.log(this.form)
        }
      }
    }
  </script>

大致的封装逻辑就这样了,需要加以补充的,依葫芦画瓢就行了~~~

Logo

前往低代码交流专区

更多推荐