首页 > 其他分享 >前端配置化表单组件设计方法

前端配置化表单组件设计方法

时间:2023-05-06 18:34:06浏览次数:46  
标签:code name title column 前端 表单 组件 true

一、背景

前端开发中涉及表单的页面非常多,看似功能简单,开发快速,实则占去了很大一部分时间。当某个表单包含元素过多时还会导致html代码过多,vue文件过大。从而不容易查找、修改和维护。为了提高开发效率及降低维护成本,下面介绍表单配置化组件的封装原理与封装方法。

二、技术方案

如上图所示,封装表单配置化组件的关键点有三个一是如何解决表单元素排布的行列问题,二是表单数据的绑定问题,三是表单元素的参数配置校验等问题。下面分别介绍这三个问题的解决方法。

•配置化表单组件的入参及说明

参数 说明 类型 可选值 默认值
labelWidth 表单元素label所占宽度 String —— 150px
columnList 表单元素所组成的配置,是一个数组 Array —— []
formData 表单元素值的集合 Object —— {}
columnSpan 表单排布分栏 Number —— 24
size 表单元素尺寸 String medium / small / mini medium

•计算配置化表单的行数,本表单通过基础的24分栏计算表单最终的行数和列数,通过下面方法最终得到一个关于行列的二维数组

newColumnList() {
  const newColumnList= []
  const row = Math.floor(24 / this.columnSpan)
  let newColumnItem = []
  for(let i=0; i< this.columnList.length; i++) {
    newColumnItem.push(this.columnList[i])
    if(newColumnItem.length === row || i === this.columnList.length-1) {
      newColumnList.push(newColumnItem)
      newColumnItem = []
    }
  }
  return newColumnList
}

•通过上面得到的二维数组进行循环渲染,首先循环渲染行,其次循环渲染列。本方案采用element中的表单,当然也可以用其他组件库或者原生表单进行渲染,其原理通用。最终将会根据参数column.type决定加载哪一个具体的表单元素。

<el-form ref="form" :model="formData" :label-width="labelWidth" :size="size">
    <el-row :gutter="20" v-for="(element,index) in newColumnList" :key="index+'formRow'">
      <template v-for="(item, index) in element" >
        <column
          :key="index + 'formView'"
          :columnSpan="columnSpan"
          :column="item"
          :formData="formData"
        />
      </template>
    </el-row>
</el-form>

•column组件最终根据type加载具体的表单元素。下面展示column组件的入参及其说明,通过component加载不同的表单元素

参数 说明 类型 可选值 默认值
column 表单元素的具体配置 Object —— {}
formData 表单元素值的集合 Object —— {}
columnSpan 表单排布分栏 Number —— 24
<el-col :span="columnSpan">
     <component
      :is="column.type + 'View'"
      :column="column"
      :formData="formData"
      v-model="formData[column.name]"
      :columnSpan="columnSpan"/>
 </el-col>

•这里主要以select表单元素为例进行说明,表单元素的双向绑定、校验以及值更新等问题

参数 说明 类型 可选值 默认值
column 表单元素的具体配置 Object —— {}
value 表单元素值 Number/String/Array —— ——

•column参数

参数 说明 类型 可选值 默认值
placeholder 空值说明 String —— ——
required 是否必填 Boolean —— ——
rules 校验规则 Array —— ——
title 表单元素label String —— ——
name 表单元素值名称 String —— ——
multiple 是否多选 Boolean —— ——
filterable 是否过滤 Boolean —— ——
disabled 是否禁用 Boolean —— ——
dictionary 下拉选项枚举 Array —— ——
changeFunction 值改变时的回调函数 Function —— ——
<el-form-item :label="column.title + ':'" :prop="column.name" :rules="rules">
    <el-select
      v-model="val"
      clearable
      :multiple="column.multiple"
      :filterable="column.filterable"
      :placeholder="'请选择' + column.title"
      :disabled="column.disabled"
      style="width: 100%"
      @change="onChange"
      @clear="onClear">
      <el-option v-for="item in column.dictionary" :key="item.code" :label="item.name" :value="item.code">
      </el-option>
    </el-select>
</el-form-item>

rules:  [
    {
      required: this.column.required,
      message: this.column.placeholder placeholder ? this.column.placeholder : `请输入${this.column.title}`,
      trigger: 'change'
    },
    ...this.column.rules
 ]

onChange(){
  this.$emit('input',this.val)
  if(this.column && this.column.changeFunction){
    this.column.changeFunction(this.val)
  }
},
onClear(){
  this.onChange()
}

三、项目实践

•配置化表单为bs-form,在页面中引入bs-form表单组件

<bs-form ref="formDemo"
     :columnList="columnList"
     :formData="formData"
     :columnSpan="columnSpan"
     labelWidth="120px">
</bs-form>
<el-row style="text-align: center;">
  <el-button type="primary"
             @click="onSave">保存</el-button>
  <el-button @click="onCancel">取消</el-button>
</el-row>

•formData参数

formData: {
    name: '',
    yearIncome: '', // 业务类型
    goodsCategoryId: '', // 托寄物品类id
    projectManagerErp: '', // 项目经理erp
    projectName: '', // 项目名称
    projectStage: '', // 项目阶段编码
    projectStandardName: '', // 标准名称
    projectYear: 2023, // 年份
    startRegionId: '', // 始发区域id
    startBattleId: '', // 始发战区id
    address: [], // 省市
    category: null, //图文类型
    range: [] //发布范围
 }

•分栏参数

columnSpan: 6

•表单配置参数

columnList(){
  const self = this
  return [
    {
      type: 'text',
      name: 'name',
      title: '项目名称',
      required: true,
      maxlength: 20,
      showwordlimit: true,
      placeholder: '请输入'
    },
    {
      name: 'category',
      type: 'radio',
      dictionary: [
        {
          code: 1,
          name: '类型一'
        },
        {
          code: 2,
          name: '类型二'
        }
      ],
      title: '图文类型',
      required: true
    },
    {
      name: 'range',
      type: 'checkbox',
      title: '发布范围',
      dictionary: [
        {
          code: 1,
          name: '范围一'
        },
        {
          code: 2,
          name: '范围二'
        }
      ],
      required: true
    },
    {
      type: 'text',  // 字段类型文本框
      name: 'yearIncome',  //与后台对接字段
      title: '年均收入',  // 前端展示字段
      required: true, // 必填项设置
      maxlength: 50,  // 字符串长度限制
      showwordlimit: true, // 是否显示字符串长度
      placeholder: '请输入', // 占位文本提示
      rules: [
        { pattern: /(^[1-9]([0-9]+)?(.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9].[0-9]([0-9])?$)/, message: '请输入数字最多两位小数' }
      ],
    },
    {
      type: 'select',
      name: 'goodsCategoryId',
      title: '托寄物品类',
      required: true,
      filterable: true,
      placeholder: '请选择',
      dictionary: [{
        name: '苹果',
        code: '1'
      },{
        name: '手机',
        code: '2'
      },{
        name: '测试',
        code: '3'
      },{
        name: '樱桃',
        code: '7'
      },{
        name: '荸荠',
        code: '9'
      }]
    },
    {
      type: 'select',
      name: 'startRegionId',
      title: '区域',
      required: true,
      placeholder: '请选择',
      dictionary: [{
        name: '销售-华北区域',
        code: '1'
      },{
        name: '销售-华东区域',
        code: '2'
      },{
        name: '销售-华南区域',
        code: '3'
      },{
        name: '销售-西南区域',
        code: '4'
      },{
        name: '销售-华中区域',
        code: '5'
      },{
        name: '销售-东北区域',
        code: '6'
      }],
      // 点击下来触发切换联动的事件,为一个函数
      changeFunction: function (val) {
      }
    }, {
      type: 'select',
      name: 'startBattleId',
      title: '战区',
      required: true,
      placeholder: '请选择',
      dictionary: this.battleByRegionList
    }, {
      type: 'select',
      name: 'projectStage',
      title: '项目阶段',
      required: true,
      placeholder: '请选择',
      dictionary: [{
        name: '项目发起阶段',
        code: '10'
      },{
        name: '项目调研阶段',
        code: '20'
      },{
        name: '可行性分析阶段',
        code: '30'
      },{
        name: '立项阶段',
        code: '40'
      }]
    }, {
      type: 'text',
      name: 'projectStandardName',
      title: '标准名称',
      required: true,
      placeholder: '请输入',
      append: '.com',  // 文本框后置内容
    }, {
      type: 'text',
      name: 'projectManagerErp',
      title: '项目经理',
      required: true,
      placeholder: '请输入'
    },{
      type: 'cascader',  // 字段类型下拉框
      name: 'address',   //与后台对接字段
      title: '省市区',  // 前端展示字段
      required: true, // 必填项设置
      placeholder:'请选择',  // 占位文本提示
      dictionary: [{
        value: 'shanxi',
        label: '陕西省',
        children: [{
          value: 'xian',
          label: '西安市',
          children: [{
            value: 'yanta',
            label: '雁塔区'
          }, {
            value: 'beilin',
            label: '碑林区'
          }, {
            value: 'xincheng',
            label: '新城区'
          }, {
            value: 'weiyang',
            label: '未央区'
          }]
        }]
      }],
      // 点击下来触发切换联动的事件,为一个函数
      changeFunction: function(){}
    },{
      type: 'static',
      name: 'projectYear',
      title: '年份'
    }
  ]
}

•表单保存

// 保存
async onSave() {
  const valid = await this.$refs.formDemo.onValidate()
  if(valid) {
    this.$message.success('校验通过')
  }else {
    this.$message.error('校验失败')
  }
}

四、成果展示

作者:京东物流 田雷雷

标签:code,name,title,column,前端,表单,组件,true
From: https://www.cnblogs.com/Jcloud/p/17378240.html

相关文章

  • 前端自定义分页
    <el-tablesize="mini"stripeborderfitheight="406px"highlight-current-row:header-cell-style="{background:'#F0F3F8'}":data="historyResearch......
  • 提高效率的自定义表单工具!
    在信息化快速发展的今天,传统的表单制作工具在办公自动化环境中局限性很多,不利于企业提升办公协作效率。自定义表单工具的出现,让数据资源得到归拢和整理,表单制作更为简单和明了,今天,我们就一起来看看自定义表单工具的优势、特点等相关知识吧。1、自定义表单工具的优势在线表单制作......
  • vue编码一个简单的组件
    基于上一篇博客,现在我来学一下,如何根据vue编写一个简单的组件第一步:导入vue.js模板第二步:代码编写,定义一个Vue组件component第三步:还是需要id填写app调用这个scriptzujianmingcheng==组件名称(自定义的)全部代码演示<!DOCTYPEhtml><htmllang="en"xmlns:v-bind="http:......
  • 前端性能优化
    1.如果应用层响应超时怎么处理解决?如果响应超时,可以采取以下措施来处理解决:增加超时时间:可以增加请求的超时时间来尝试避免响应超时。可以在发起请求时,设置超时时间,如果在指定时间内未收到响应,则认为响应超时。减少请求负载:如果请求负载过大,服务器响应可能会受到影响,从......
  • 宜搭应用中修改子表单字体大小
    在浏览器模式下找到对应字体的<div>标签,赋值其class名到布局容器的源码编辑器中修改其样式说明:浏览器中字体显示最小值是12px,组件需放入布局容器 ......
  • 前端知识点,资源,项目资源
    中级前端需要掌握的知识点JavaScript基础知识,包括ES6及以上版本的语言特性。Vue框架的核心概念和实现原理,包括组件、指令、生命周期等。React框架的核心概念和实现原理,包括JSX、组件、状态和属性等。Web性能优化,包括代码压缩、CDN加速、懒加载等技术。移动端开发,包括响应式......
  • Mac M系列芯片 vue前端node-sass兼容问题解决
    0、由于M系列芯片是arm架构,在使用brew安装node时都是arm的node,但是[email protected]版本中不支持arm架构的出现如下报错:Error:NodeSassdoesnotyetsupportyourcurrentenvironment:OSXUnsupportedarchitecture(arm64)withUnsupportedruntime(88)Formoreinfor......
  • django内置序列化组件(drf前身)
    目录一、django内置序列化组件(drf前身)一、django内置序列化组件(drf前身)一、django内置序列化组件(drf前身)这里的内置序列化组件,其实就是实现将后端数据,存放到字典中或是存放到列表中有序输出。这里是我们用JsonResponse模块自己实现的代码'''前后端分离的项目视图函数......
  • 一统天下 flutter - widget 自定义: 通过 SingleChildRenderObjectWidget 实现自定义
    源码https://github.com/webabcd/flutter_demo作者webabcd一统天下flutter-widget自定义:通过SingleChildRenderObjectWidget实现自定义组件示例如下:lib\widget\custom\single_child_render_object_widget.dart/**通过SingleChildRenderObjectWidget实现自......
  • 一统天下 flutter - widget 自定义: 通过 CustomPaint 实现自定义组件
    源码https://github.com/webabcd/flutter_demo作者webabcd一统天下flutter-widget自定义:通过CustomPaint实现自定义组件示例如下:lib\widget\custom\custom_paint.dart/**通过CustomPaint实现自定义组件**CustomPaint继承自SingleChildRenderObjectW......