Vue每天学一点Vue3

Vue3组件(九)封装一个长大的表单(上)

2021-02-20  本文已影响0人  自然框架

一个神奇的表单

表单表单,你已经长大了,你要学会自己:

实现多行多列的表单

首先感谢 el-form,真的很强大,不仅好看,还提供了验证功能,还有很多其他的功能。
只是好像只能横着排,或者竖着排。那么能不能多行多列呢?似乎没有直接提供。

我们知道 el-row、el-col 可以实现多行多列的功能,那么能不能结合一下呢?官网也不直说,害的我各种找,还好找到了。(好吧,其实折腾了一阵着的table)

二者结合一下就可以了,这里有个小技巧,el-row只需要一个就可以,el-col可以有多个,这样一行排满后,会自动排到下一行。

  <el-form ref="form" :model="formModule" label-width="130px">
      <el-row>
        <!--不循环row,直接循环col,放不下会自动往下串行。-->
        <el-col :span="8">
           <!--假装有好多好多的el-col-->
           <el-form-item :label="姓名:">
              <!--这里可以放组件-->
          </el-form-item>
        </el-col>
      </el-row>
    </el-form>

这样有什么好处呢?当然是便于我们做v-for呀,给 el-col 加上 v-for 就好。

实现动态渲染功能

表单嘛,那么多字段一个一个做多麻烦,v-for 一下不香吗?
前面封装了那么多的组件,就是为了可以 v-for。

首先准备一个json文件,里面放置需要的组件的属性。


003表单的json.png

json比较长,我们还是看截图吧,直观一些。

然后用 require 读取进来,当然也可以用 axios 来读取。

然后表单控件就可以用这些属性做循环了。

另外还有几个附带功能:

自动创建 model

我比较懒,手撸 model 是不是有点麻烦?如果能够自动获得该多好,于是我写了这个函数。

  // 创建 v-model
  const createModel = () => {
    // 依据meta,创建module
    for (const key in formItemMeta) {
      const m = formItemMeta[key]
      // 根据控件类型设置属性值
      switch (m.controlType) {
        case 100: // 文本类
        case 101:
        case 102:
        case 103:
        case 104:
        case 105:
        case 106:
        case 107:
        case 130:
        case 131:
          formModel[m.colName] = ''
          break
        case 110: // 日期
        case 111: // 日期时间
        case 112: // 年月
        case 114: // 年
        case 113: // 年周
          formModel[m.colName] = null
          break
        case 115: // 任意时间
          formModel[m.colName] = '00:00:00'
          break
        case 116: // 选择时间
          formModel[m.colName] = '00:00'
          break
        case 120: // 数字
        case 121:
          formModel[m.colName] = 0
          break
        case 150: // 勾选
        case 151: // 开关
          formModel[m.colName] = false
          break
        case 153: // 单选组
        case 160: // 下拉单选
        case 162: // 下拉联动
          formModel[m.colName] = null
          break
        case 152: // 多选组
        case 161: // 下拉多选
          formModel[m.colName] = []
          break
      }
      // 看看有没有设置默认值
      if (typeof m.defaultValue !== 'undefined') {
        switch (m.defaultValue) {
          case '':
            break
          case '{}':
            formModel[m.colName] = {}
            break
          case '[]':
            formModel[m.colName] = []
            break
          case 'date':
            formModel[m.colName] = new Date()
            break
          default:
            formModel[m.colName] = m.defaultValue
            break
        }
      }
    }
    // 同步父组件的v-model
    context.emit('update:modelValue', formModel)
  }

可以根据类型和默认值,设置model的属性,这样就方便多了。

多列的表单

这个是最复杂的,分为两种情况:单列的挤一挤、多列的抢位置。

单列

单列的表单有一个特点,一行比较宽松,那么有时候就需要两个组件在一行里显示,其他的还是一行一个组件,那么要如何调整呢?

这里做一个设定:

这样记录之后,我们就可以判断,≥1的记做span=24,负数的,用24去除,得到的就是span的数字。当然记得取整数。

为啥用负数做标记呢?就是为了区分开多列的调整。

多列

多列的表单有一个特点,一个格子比较小,有些组件太长放不下,这个时候这个组件就要抢后面的格子来用。

那么我们还是做一个设定:

这样记录之后,我们可以判断,≤1的,记做 24 / 列数,大于1的记做 24/ 列数 * n。
这样就可以了,可以兼容单列的设置,不用因为单列变多列而调整设置。
只是有个小麻烦,占得格子太多的话,就会提取挤到下一行,而本行会出现“空缺”。
这个暂时靠人工调整吧。
毕竟哪个字段在前面,还是需要人工设置的。

一顿分析猛如虎,一看代码没几行。

  // 调整行列
  const span = reactive({})
  // 根据配置里面的colCount,设置span
  const getSpan = () => {
    const formColCount = formMeta.formColCount // 列数
    const moreColSpan = 24 / formColCount // 一个格子占多少份

    if (formColCount === 1) {
    // 一列的情况
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          span[m.controlId] = moreColSpan
        } else {
          if (m.colCount >= 1) {
            // 单列,多占的也只有24格
            span[m.controlId] = moreColSpan
          } else if (m.colCount < 0) {
            // 挤一挤的情况, 24 除以 占的份数
            span[m.controlId] = moreColSpan / (0 - m.colCount)
          }
        }
      }
    } else {
      // 多列的情况
      for (const key in formItemMeta) {
        const m = formItemMeta[key]
        if (typeof m.colCount === 'undefined') {
          span[m.controlId] = moreColSpan
        } else {
          if (m.colCount < 0 || m.colCount === 1) {
            // 多列,挤一挤的占一份
            span[m.controlId] = moreColSpan
          } else if (m.colCount > 1) {
            // 多列,占的格子数 * 份数
            span[m.controlId] = moreColSpan * m.colCount
          }
        }
      }
    }
  }

最后看看效果,可以动态设置列数:

动态表单001.gif

如果空间够的话,最多可以是24列。应该是够用了。

上一篇 下一篇

猜你喜欢

热点阅读