web表单设计代码,前端表单设计

一、背景

前端开发中涉及表单的页面非常多,看似功能简单,开发快速,实则占去了很大一部分时间。当某个表单包含元素过多时还会导致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('校验失败')

  }

}

四、成果展示

本文来自投稿,不代表展天博客立场,如若转载,请注明出处:https://www.me900.com/325503.html

(0)

相关推荐

  • 河南vps,河南科技大学

    以下是一篇关于“河南vps”的文章: 一、什么是河南vps 河南vps可能是指在河南地区部署的虚拟专用服务器(VirtualPrivateServer)。它就像是在河南这片土地上搭建的一个独立的服务器空间,通过网络技术将其与其他网络隔离,为用户提供相对独立的计算和存储环境。 我觉得它有点像在河南的一个专属“小房间”,你可以在这个“小房间”里自由地进行各种操作…

    2025-07-29
  • 淘抢购入口,淘抢购是真的便宜吗

    《淘抢购入口:探索电商促销的便捷通道》 在如今繁华的电商世界中,淘抢购入口犹如一颗璀璨的明珠,散发着独特的魅力。 它仿佛是一扇通往购物狂欢的大门,为消费者带来了无尽的惊喜与实惠。 那么,淘抢购入口究竟是什么?它又有着怎样的特点和魅力呢?让我们一起深入探索。 一、淘抢购入口的基本概念 淘抢购入口,简单来说,就是淘宝平台上专门用于展示和推广各类限时抢购活动的通道…

    2025-05-16
  • 淘宝上买东西如何省钱,在网上买东西省钱的办法

    淘宝上买东西如何省钱,在网上买东西省钱的办法淘宝上买东西如何省钱,在网上买东西省钱的办法淘宝上买东西如何省钱,在网上买东西省钱的办法淘宝上买东西如何省钱,在网上买东西省钱的办法

    作为一个玩钢笔的,平时爱好花销肯定很大,然而我是学生党(初中),所以肯定要有点省钱技巧才行嘛。 这篇文章,就是介绍一下,我薅的羊毛们(每篇文章介绍20个,具体有几篇以后再说)。 1、日用消耗品去阿里巴巴买: 比如说笔(以得力S01举例): 价格差不多,却有两倍的量! 再比如说纸(以维达抽纸为例): 京东10包19.9元。 阿里巴巴大概能买30包。 当然了阿里…

    2022-04-22 投稿
  • 如何在农村买地建房?城市户口在农村建房

          问:老家是农村的,但是户口是城市户口。怎么才能在老家建房?想在老家的老房子重建,怎么才能重建?       永州市农业农村局关于农村房怎么建房的答复   尊敬的网友: 您好,关于《农村房怎么建房》已收悉,现答复如下: 1.关于“老家是农村的,但是户口是城市户口,怎么才能在老家建…

    2022-04-17
  • 大和尚惠斌结局,惠斌欧阳修的正式弟子有哪些

    九罪证凶僧是《童林传》中非常精彩的一个回目,大和尚惠斌号称“金鸡好斗双钢掌赤胆侠”,他与一个地方很有渊源,这个地方就是挡僧岭。可以说惠斌成也在挡僧岭,败也在挡僧岭,小时候的惠斌跟随天海佛窦瑞学艺,窦瑞的师父是八十一门的总门掌欧阳修,经过欧阳修的同意,窦瑞代师传艺教给惠斌能耐,所以说惠斌也算是欧阳修的正式弟子。 惠斌的确是练武的奇才,他起早贪黑下了十年的苦工就…

    2023-06-16
  • 超级机器人大战z2,天津地铁z2线中标公示

    津滨海讯(记者 戈荣喜 通讯员 宋邦华 刘贾飞 摄影报道)4月的滨城春风习习,春意融融。位于滨海新区创新大道的天津市轨道交通Z2线04标施工现场,机器的轰鸣声伴随着忙碌的施工工人的身影构成了项目冲刺前进的“协奏曲”和跳动的“音符”。4月20日,天津市轨通Z2线一期工程PPP项目“Z2线上党旗红”大党建、“六个示范”廉洁线创建、“五保一树”劳动竞赛活动启动仪式…

    2023-07-03
  • 快乐星球莲蓉包(快乐星球的成员都有谁)

    每个人都有属于自己的童年回忆,童年或许是一幅画,或许是一条河,也可能是一首歌,还可能是一个小零食,对于很多人来说,童年是一部剧。 对于多数90后来说,童年是由无数个电视剧组成的,比如《家有儿女》《武林外传》又或者是《快乐星球》,想必众多家长应该都陪着孩子看过这几部剧。 如今回想起来,《快乐星球》的剧情似乎非常无厘头,但它却小孩子们送去了一个奇幻又美好的童年。…

    2023-06-15
  • 参苓健脾胃颗粒的功效与作用,参苓健脾胃颗粒胖人能吃吗

    在一线的药学服务中,常遇到有很多种中成药名字相近,或相似的情况,如健脾丸,启脾丸,开胃理脾丸,参苓健脾胃颗粒,那么他们有什么不一样呢?同功效吗?遇到脾胃不和的情况,是否可以替换使用?今日,玥亮说药带着这些常见的问题给大家说说!   健脾丸 健脾丸,具有健脾开胃的功效。本方由党参、炒白术、陈皮、枳实、炒山楂、炒麦芽组成。用于脾胃虚弱,脘腹胀满,食少便…

    2023-06-24
  • 可以月入过万的线上副业(大家可以推荐好一点的副业)

    可以月入过万的线上副业(大家可以推荐好一点的副业)可以月入过万的线上副业(大家可以推荐好一点的副业)可以月入过万的线上副业(大家可以推荐好一点的副业)可以月入过万的线上副业(大家可以推荐好一点的副业)

    几乎所有的上班族,都有一个发财梦,希望自己能够通过努力快速升职加薪,赚得盆满钵满。 当然,也有不少人实现了这样的梦想,但是绝大多数人的梦想,永远只能是“想”,也就是光想不做。 光靠8小时之内的工作时间,肯定不足以养活自己,想要真正赚到钱,必须要靠8小时之外的努力和工作。 最近越来越流行一个词,叫做“副业刚需”,副业就是我们独一无二的选择,当你觉得自己工资低的…

    2022-01-09 投稿
  • 龙珠超黑悟空,黑悟空是怎么诞生的

    龙珠超黑悟空,黑悟空是怎么诞生的龙珠超黑悟空,黑悟空是怎么诞生的龙珠超黑悟空,黑悟空是怎么诞生的龙珠超黑悟空,黑悟空是怎么诞生的

    龙珠超中的黑悟空,从设定上看就是一个拥有赛亚人野性的另一个悟空。准确的可以说:我觉得黑悟空就是没有失忆的悟空,该会有的样子了。为什么这么说呢?我来谈谈我的一些观点。 首先,我们知道,悟空是被送来地球的。但是,在悟空送来地球的时候,悟空的性格并不是现在我们所看到的单纯,仁慈的一个人。而是一个充满了赛亚人野性,和谁都合不来,只想破坏的赛亚人。   但是…

    2023-07-04 投稿
  • 外国人穿秋裤吗(外国人冬天穿秋裤吗)

    外国人穿秋裤吗(外国人冬天穿秋裤吗)外国人穿秋裤吗(外国人冬天穿秋裤吗)外国人穿秋裤吗(外国人冬天穿秋裤吗)外国人穿秋裤吗(外国人冬天穿秋裤吗)

    对于拥有老寒腿的我来说,如今的天气,我不得不翻越重重的阻碍,找到了我的秋裤,没有秋裤的人生是不完美的。对于一个中国小孩来说,秋裤伴终生。小的时候同学们常说,你冷不冷你妈妈觉得冷就是冷,你妈妈让你穿秋裤,你不穿也得穿,可见中国妈妈对秋裤的热爱。我猜大家一定不知道外国人是不穿秋裤的,而且在外国你也找不到卖秋裤的。大家都知道,外国的冬天比我们这里更冷,正常情况下不…

    2023-05-24 投稿
  • 因私护照可以异地办理吗?2022因私护照什么时候恢复办理

    1丨出国旅游等因私护照办理和换发恢复了?假的! 每经AI快讯,近日,有群众向国家移民管理局查询求证,“网上流传北京等地恢复了出国旅游等因私护照办理和换发,是否属实?现在以普通探亲、旅游等事由出境,可以换发护照吗?”国家移民管理局郑重提醒,相关网上信息为不实消息!当前,境外疫情形势依然严峻,跨境旅行等存在较大安全风险。国家移民管理局倡导非紧急非必要不出境。但对…

    2022-04-11