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

一个神奇的表单

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

  • 排成一列
  • 排成一行
  • 验证表单数据
  • 排成方队
  • 合并调整
  • 动态渲染
  • 支持 item 扩展组件
  • 可以自动创建 model

实现多行多列的表单

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

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

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

  
      
        
        
           
           
              
          
        
      
    

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

实现动态渲染功能

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

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


003表单的json.png

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

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

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

另外还有几个附带功能:

  • 支持单行下的合并。
    在单行的情况下,一些短的控件会比较占空间,我们可以把多个小的合并到一行。

  • 支持多行下的扩展。
    多行的情况下,一些长的控件需要占更多的空间,我们可以设置它多占几个格子。

  • 自动创建表单需要的 model。
    不需要手动写 model了。

自动创建 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
  • 两个组件挤一行的,记做-2
  • 三个组件挤一行的,记做-3
    以此类推,理论上最多支持-24,当然实际上似乎没有这么宽的显示器。

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

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

多列

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

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

  • 一个组件占一格的,还是记做1
  • 一个组件占两格的,记做2
  • 一个组件占三格的,记做3
    以此类推。

这样记录之后,我们可以判断,≤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列。应该是够用了。

你可能感兴趣的:(Vue3组件(九)封装一个长大的表单(上))