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('校验失败')

  }

}

四、成果展示

本站部分内容由互联网用户自发贡献,该文观点仅代表作者本人,本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如发现本站有涉嫌抄袭侵权/违法违规等内容,请联系我们举报!一经查实,本站将立刻删除。

(0)

相关推荐

  • 烤箱烤鱼温度和时间(烤箱烤鱼上下火一起烤吗)

    做烤鱼而言,鱼要薄一些,这样既能腌制入味,又能尽快烤熟。就鱼类而言,淡水鱼选草鱼,海水鱼选带鱼、面包鱼、偏口鱼和鱿鱼都可以。那烤箱烤鱼的温度和时间设定是怎样的呢?   烤箱烤鱼的温度和时间 将鱼洗净,从腹部到头部一开为二,背部相连。用盐、料酒、花椒面、胡椒粉葱段、姜片、蒜瓣涂抹鱼身腌渍入味(打开烤箱上下火,200度提前预热);将鱼放入烤盘,200度…

    投稿 2022-05-12
  • google网赚(谷歌广告联盟靠谱吗)

    据外媒报道,一位Reddit用户发现,Google Task Mate是一款可以让印度用户通过在智能手机上完成简单任务来赚钱的应用。这款应用目前处于beta测试阶段,只能通过推荐码加入,不过该应用可以从Google Play Store下载到。用户完成的任务将以当地货币支付,应用会显示任务的价值。 这些任务被分类为就座任务或实地任务,该应用还会显示完成的任务…

    2021-11-14
  • 农夫山泉创始人成中国首富名字

    大家好,我是陈科磊,今天咱们聊聊农夫山泉创始人钟睒睒的故事,睒睒读音shanshan,可以理解为闪闪的意思。 钟睒睒,1954年人,今年67岁,出生在浙江省绍兴市诸暨市,五年级因为父母被打为右派辍学,辍学后他学过瓦匠、干过木匠,1977年高考恢复,他23岁,参加了高考,考了3年,考上了杭州电大中文系。 毕业后他先去了省文联,管理基建,后又去了《江南》杂志社、…

    2022-04-25 投稿
  • Xtrabackup备份与恢复,备份系统恢复到新硬盘

    概述 今天主要通过一个实验来简单介绍一下如何用XtraBackup 实现全备&增量备份与恢复的全过程~ 官方手册:https://www.percona.com/doc/percona-xtrabackup/2.4/index.html 一、xtrabackup备份过程解析 第一阶段:检查与连接的准备阶段 执行备份命令之后,备份开始,XtraBack…

    2023-06-29
  • 灵媒简介,灵媒简介人物关系介绍

    《灵媒》 by风流书呆文案:不知道你听没听说过,世界上有这么一种人,他们并不需要任何实质性的接触,只需一丝灵光或一个闪念,就能获悉很多东西。 他们的眼睛能洞穿过去、明晰现在,堪破未来。他们能透过你的眼看见你的所见,也能透过你的鼻嗅见你的所闻,亦能透过你的舌尝见你的所尝,甚至能透过你的心窥探你的所想。 这种人,被外界称之为——灵媒。 一句话简介:总结就是,主角…

    2023-06-25
  • 好看的年代文完结推荐(年代文小说推荐经典排行)

    同为书迷的小编,我给大家整理了六本巨爽年代文小说,爽文,穿越时空,穿书,种田文, 快穿, 女配, 重生 。让你分分钟看上瘾不睡觉!记得收藏哦,以后就不怕再书荒啦!   目录   1.《七零之穿成男主前妻》 作者:元月月半   2.《咸鱼穿成年代文炮灰[快穿]》 作者:雨落窗帘   3.《穿到年代文中搞科研[穿书]》 作…

    2023-06-18 投稿
  • 个人征信官网查询(全国个人征信查询官网)

    1 手机APP查询 各银行APP如下: (图来自网络) 用招商银行APP查询,不会留下查询记录。 2 网银查询 通过登录招商银行个人网银的方式进行查询。 (图片来自网络) 3 征信中心查询 通过互联网登录“中国人民银行征信中心”官网(www.pbccrc.org.cn)查询,要注册账号,还要安装数字证书等控件,有点小耐心。 (图片来自网络) 4 自助机网查询…

    2021-12-04 投稿
  • 2023年我国会出现一个世界巨星(2023年世界巨星是谁)

    曼联官方宣布跟尤文达成协议,将跟C罗签约至2023年。   什么叫国际巨星!曼联在官宣C罗回归后,他们的官网直接瘫痪了。据了解,曼联俱乐部的股价也上涨8.39%! 《阿斯报》记者感叹这是史上最佳的转会窗。前曼联7号欧文也来凑热闹:“这比梅西转会巴黎还轰动!但所有人都认为C罗会去曼城的时候,结果他回归了曼联。”   曼联拥趸鹿晗也在深夜发微…

    2022-02-20 投稿
  • 白俄罗斯人口多少面积多大?俄罗斯人口和国土面积是多少

    1547年,伊凡四世(伊凡雷帝)改大公称号为沙皇。1721年,彼得一世(彼得大帝)改国号为俄罗斯帝国。 【俄罗斯帝国】 俄罗斯帝国又称沙皇俄国或沙俄,时间跨度是1721年-1917年,定都圣彼得堡,只有1728-1730这几年临时在莫斯科。 俄罗斯帝国曾占据阿拉斯加,1867年, 720万美元卖给了**。 俄罗斯帝国与清朝先后签订中俄《瑷珲条约》《北京条约》…

    2023-02-07 投稿
  • 扬州泰州机场招聘,扬州泰州机场招聘求职招聘信息发布

    扬泰机场8月可直飞丽江、丹东 扬泰机场位于扬州市江都区丁沟镇,距扬州市区约25公里、泰州市区约20公里,跑道长3200米,飞行区**4E。 通航以来,机场共累计开通东京、大阪、首尔、曼谷、北京、成都、深圳、广州、西安等多条国内外热点城市航线,并引进5架驻场飞机。 2018年机场全年完成旅客吞吐量238.42万人次,同比增长29.8%,完成货邮吞吐量1.11万…

    投稿 2023-04-23
  • 女演员李健个人资料简介(演员李健简介个人简历)

    进得了名校、捧得上奖杯, 有人问:有些明明可以靠脸吃饭的明星,为啥偏偏靠才华?   但2021年发生的“娱乐圈大地震”却告诉所有人: 只有真正有内涵、有才华的艺人,才能玩转人生, 而那些浮于表面的华丽终将会褪色。 今天就来盘点一下,那些毕业于世界顶尖院校的明星们。 1、“音乐诗人”李健,清华大学 对于8090来说,对“水木年华”组合的名字一定不陌生…

    2022-01-02 投稿
  • 网盘赚钱平台(网盘点击浏览赚钱)

    自从网盘倒闭潮后,中国市场的网盘产品很长一段时间内都处于“销声匿迹”状态,一方面,要跟盗版以及不良内容做斗争,另一方面,在新的盈利模式探索上又迟迟没有找到对的方向,不低调不行,但低调的另一面,则是用户对网盘产品创新的感知度低,网盘的存在感也在降低。 目前市场上的免费网盘产品主要有三款,百度网盘、腾讯微云、115,而付费的网盘产品则比较多,新浪微盘、360云盘…

    2022-01-23