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)

相关推荐

  • 黑荆棘角斗场,残酷角斗士的拯救

    大家是怎么了解到”角斗士“的呢? 我第一次接触“角斗士”这个词大概是在小学三年级,那时候的我从老爸的书柜里淘了一本叫《斯巴达克斯》的外国小说。 大概长这样(ps.小说真的挺好看) 现在想来,那本薄薄的、黄色封皮的、还总是有错别字的书很可能是一个劣质的盗版译本,但那个在罗马圆形决斗场里,作为奴隶角斗士的斯巴达克斯在一场15V15的死斗中杀死所有敌人,赢得罗马观…

    2023-07-10 投稿
  • 邓婕女儿 ,邓婕和张国立的情况

    一天,邓婕含情脉脉地对张国立说:“我们要个孩子吧。” 可张国立却冷冷地回应道: “你要是觉得寂寞,就养条狗吧,别提生孩子的事了。” 后来邓婕真的养了很多条狗,却始终没能有个自己的孩子。 婚后不久,他们就有了儿子张默。1983年,他们夫妻俩进入四川人民艺术剧院,张国立开始向演艺圈进军,拍摄了人生中的第一部电视剧。 正所谓万事开头难,初入影视圈的前几年,没有背景…

    2023-06-05 投稿
  • 笔记本电脑除尘(笔记本电脑除尘要多久)

    大家好,今天分享一篇来源小白一键重装网(www.xiaobaixitong.com)关于解答:笔记本电脑清灰教程。 万年不清灰的笔记本电脑会成什么样?相信很多用户都不知道如何清理电脑灰尘,也不敢自己动手,担心自己不小心将电脑弄坏。 但笔记本电脑用久了,也会像台式一样积满灰尘,如果不清理,积满了灰尘导致散热性能降低,你的笔记本电脑将会又慢又卡,甚至在这30多度…

    2023-06-08 投稿
  • 哪个返利网返利最高(哪个返利网返利最高最安全)

    我是一个比较喜欢网上购物的人,特别是淘宝上面购物,虽然听别人说淘宝网上面假货比较多,但是说实话,我在淘宝网上面有几百次购物经历,却是却从来都没有买到过假货,至少我没有发现我买的东西中有假货。 我也是一个比较喜欢省钱的人,现在有一些返利APP会返还一部分淘宝的购物经额给买家,并且所有的交易操作都是淘宝网上面完成的。刚开始的时候我也不相信,于是我就报着试一试的心…

    2021-12-26 投稿
  • 一个家庭怎么省钱存钱(高中生如何省钱和存钱)

    省钱这件事,每个人的理由都不一样,有的人是因为没钱,经济拮据而省钱,有人是因为未来的种种未知和不确定性而省钱,有人是为了实现财务自由,提前退休,还有人是为了不消费主义的快乐。   极简省钱以来,我已经不是从前的自己,感觉自己已经彻底变了一个人。生活的方方面面都发生了翻天覆地的变化。   或许在别人看来,省钱存钱一定是痛苦遭罪,但是在我而言…

    2021-12-30 投稿
  • 快递公司业务员,调研快递员职业操作规范

    近期北京、上海、大连、重庆等国内多地居民陷入“快递不快”的困境,原本两三天就能到的快递包裹迟迟不见配送。 有北京快递小哥告诉南都、N视频记者,受疫情影响,前一段时间不少同事生病,导致快递点人手短缺,但近日同事们都返岗,站点也正恢复常态。上海也有快递小哥介绍,站点存在快递员数量减少的现象,但站点机动人员已全部顶上。 面对眼前的困境,多家快递公司向南都记者表示,…

    2023-06-02
  • 江西豆葱的做法(豆葱烧肉做法大全)

    浓油赤酱的红烧肉一直是餐桌上经常一扫而光的家常菜,选用的是五花肉肥瘦相间,咬上一口非常有满足感。不过上次在健康节目里听说需要多吃一些发酵物,所以今天这道烧肉,选用豆瓣酱进行烧制,也非常下饭好吃,选用的猪腿肉相对脂肪含量更少一些,更加健康。 By polaris滴食记 【豆果美食官方认证达人】 用料 猪腿肉 500g葱 5g六月香葱伴侣豆瓣酱 2勺味达美臻品料…

    2022-05-12 投稿
  • pr劫持是什么意思,PR与BR的区别

    虽然,谷歌PR早已停止更新,但如果你今年在关注域名抢注市场,你会发现一个有兴趣的现象,那就是PR值高的域名,经过竞价,价格是一路水涨船高。 这很明显说明一个问题,高PR值的域名在建站中,一定拥有着它某种优势,这难免让我们想到另外一个名词BR,我们俗称:百度权重。   那么,PR与BR的区别,它有什么SEO参考价值呢? 在回答这个问题之前,根据以往的…

    2022-03-12
  • 自制去红血丝面膜,如何去除红血丝小妙招

    自制去红血丝面膜 1、自制去红血丝面膜之橄榄油蜂蜜面膜 材料:橄榄油、蜂蜜。 做法:取蜂蜜60克和橄榄油30克装入容器混合搅拌,隔水加热40度左右。 用法:将制作好的面膜涂到面膜纸上,覆盖于面部,20分钟后揭去洗净。 2、自制去红血丝面膜之芦荟蛋白面膜 做法:芦荟叶子一片,蛋白还有少许蜂蜜,芦荟叶子捣烂,将这三种材料混合在一起就做成了,芦荟有消炎镇定的功能,…

    2023-07-04
  • 拼多多摇一摇50元,拼多多摇一摇50元是真的吗

    《拼多多摇一摇50元:神秘背后的真相与玩法》 在如今的互联网时代,拼多多以其独特的营销模式和低价商品吸引了众多消费者的关注。 而其中的“拼多多摇一摇50元”活动,更是引起了广大用户的好奇和热议。 这个活动究竟是怎么回事?它真的能让我们轻松获得50元吗?今天,我们就一起来揭开“拼多多摇一摇50元”的神秘面纱。 一、活动介绍 “拼多多摇一摇50元”活动是拼多多平…

    2025-07-06
  • ssl加速,SSL**流量复制

    《关于SSL加速的深入探讨》 一、SSL加速的基本概念 SSL(SecureSocketsLayer)即安全套接层,它是一种用于在网络通信中提供加密和身份验证的协议。简单来说,它就像是网络通信的一把“锁”,能确保数据在传输过程中不被窃取、篡改或冒充。而SSL加速呢,也许就是通过一些技术手段,让这把“锁”更快地发挥作用,提高网络通信的效率。 我觉得就好像我们平…

    2025-08-15
  • 洗车店年底怎么搞活动?年底洗车店活动方案

    要保证洗车店稳定的客流,三人行管理咨询李老师觉得,主要应从以下三方面做起: 一、选址 选择居住密度大的,车流量多的,以及同行竞争相对较弱的地点,也就是说要选真正有需求的地点开店。 二、价格以及日常运营 不需要一味大打价格战,但价格也要确定具有竞争优势,运营方法也要参照同行或竞争对手,比如说别人经常做哪些有效的活动,我们要学会简单模仿,别人有加入美团等平台,我…

    2022-01-03