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)

相关推荐

  • 京东金条要还完才能借吗,京东金条是不是要还完才能借

    随着时代的发展,移动支付也在不断普及,这就使得购物消费、线上借贷等变得更为方便。在这样的时代之下,无论我们走到哪里,无论身在何处,只需轻点手机,大多数的金融需求就可以得到满足。消费者在日常生活中,也常常会遇到“哪个平台借钱方便”的问题,针对这一问题,我们可以通过对当下两大品牌即京东旗下的京东金条以及原百度旗下的有钱花的比较之后得出一个满意的答案。 &nbsp…

    2022-03-22
  • 服装尾货批发市场有哪些特点(什么是尾货市场)

    开品牌尾货服装店,就一定要学会进货。进货可是一门大学问,不仅要考虑到货源,货的款式,还要考虑到货物的价格。这些都是非常重要的。进货就一定会去到服装批发市场,那么好的服装尾货批发市场有哪些特点? 好的服装尾货批发市场有哪些特点? 1、交通便利,位置优越这是检验服装尾货批发市场是否经营成功的基础,每一个经营成功的服装尾货批发市场都是出于交通便利、位置优越的地方。…

    2023-02-04
  • 哪些人不适合黑色头发(不适合染黑色头发的人)

    哪些人不适合黑色头发(不适合染黑色头发的人)哪些人不适合黑色头发(不适合染黑色头发的人)哪些人不适合黑色头发(不适合染黑色头发的人)哪些人不适合黑色头发(不适合染黑色头发的人)

    每到过年,大街小巷所有理发店都人满为患,尤其是以女性群体居多,大家都想染个美美的头发来过新年。现在市面上大多数染发剂就是化学染发剂,植物染发剂由于价格偏高,令很多人望而却步。哈佛大学为研究永久性染发剂和癌症风险以及死亡率之间的关系,进行了长达36年的研究,所以事实的真相到底如何? 经常染发会致癌? 哈佛大学将研究结果发表在《英国医学期刊》上,研究显示:永久性…

    2022-05-10 • 投稿
  • 索泰1650毁灭者、索泰GTX1650Super毁灭者PA显卡评测

    索泰1650毁灭者、索泰GTX1650Super毁灭者PA显卡评测索泰1650毁灭者、索泰GTX1650Super毁灭者PA显卡评测索泰1650毁灭者、索泰GTX1650Super毁灭者PA显卡评测索泰1650毁灭者、索泰GTX1650Super毁灭者PA显卡评测

      入门级别的显卡市场,其竞争无疑是异常的激烈。在这个级别的显卡市场混,什么信仰、颜值所占的比重就比较小了,大家会更加看重显卡的价格和性能   预算都在这个区间了,肯定想着一分钱掰成两半用,谁能在价位更低的情况下提供更加出色的性能,谁就能抓住更多的用户,老黄自然是深谙其道   之前在入门级别显卡市场,老黄用一张GTX1650打天…

    2023-07-05 • 投稿
  • 日挣千元的跑江湖项目(职业乞丐日挣千元)

    日挣千元的跑江湖项目(职业乞丐日挣千元)日挣千元的跑江湖项目(职业乞丐日挣千元)日挣千元的跑江湖项目(职业乞丐日挣千元)日挣千元的跑江湖项目(职业乞丐日挣千元)

    在很多城市,大街小巷都会看到一些乞讨人员,他们有些穿梭在热闹的街市,有些徘徊在天桥和马路一旁,有些直接进入商家门店里上前讨要。有些乞讨者值得我们同情,但是有些却在利用人性的善良,通过欺骗获得不劳而获的钱财。   经过排查,整个区的流浪乞讨人员将近五十人左右,他们绝大多都是职业乞讨人员,其中有很多都是熟面孔,常年在这进行乞讨,已经有数十年之久。 相关…

    2021-12-06 • 投稿
  • 欢乐春节 冰岛(欢乐春节冰岛)

    冰岛,孑然独立于北大西洋,在过去的岁月中,冰岛用行动不断刷新世人对这个国度的印象,比如“维京战鼓”擂起的足球奇观。而就在前不久,一抹浓郁热烈的“中国红”登陆这片冰天雪地,为当地民众创造出另一种“奇观”。 当地时间1月25日晚,由北京市人民政府、中国驻冰岛大使馆、冰岛中国文化交流协会、冰岛中国贸易促进会、冰岛华人华侨协会主办,北京市文化和旅游局承办,北京市海外…

    2022-01-21
  • qq无法安装怎么办,qq无法安装怎么办

    《qq无法安装怎么办?全面指南与深入探讨》 一、检查设备兼容性也许在安装qq之前,我们需要先检查一下设备的兼容性。就好像你去买一双鞋,得先看看自己的脚是否适合这双鞋的尺码和款式。有些较老的设备可能无法支持qq的最新版本,就像小脚穿不下大码鞋一样。我们可以通过查看qq的官方网站或相关技术文档,了解它对设备的要求,包括操作系统版本、处理器类型、内存大小等。如果设…

    2025-11-04
  • 我的青春 日出(普法栏目剧我的青春日出)

    1月12日至13日,由北京大学歌剧研究院出品的中国歌剧《青春之歌》将登台北京天桥艺术中心大剧场,由牟天翔、黄萌、吕元杰等青年歌唱家共同上演两场。日前,本版《青春之歌》主创和主演艺术家分享了创作演出心得。 歌剧《青春之歌》改编自当代作家杨沫于1958年首次出版的长篇小说,故事以上世纪30年代日本侵华过程中所经历的“九·一八事变”及“一二·九运动”为背景,通过女…

    2022-01-20
  • 现在最流行的游戏有哪些(现在最火的游戏有哪些)

    现在最流行的游戏有哪些(现在最火的游戏有哪些)现在最流行的游戏有哪些(现在最火的游戏有哪些)现在最流行的游戏有哪些(现在最火的游戏有哪些)现在最流行的游戏有哪些(现在最火的游戏有哪些)

    现在的手游用户远比PC游戏玩家,或PS/Xbox/Switch等主机玩家多,因为人人都有手机,进行娱乐很方便,年轻人的手机上,也至少都会有两到三款常玩的手游,而且现在的手机游戏更新速度也非常快,种类繁多,有一些比较完美的,或者宣传到位的手游,常常会登上热榜,那下面就来为大家整理一下,目前人气最高的五款手游,在这些其中,绝对有一款是你经常玩的作品。 《王者荣耀…

    2021-12-14 • 投稿
  • 附近租古装汉服的地方(古色古香全是汉服)

    附近租古装汉服的地方(古色古香全是汉服)附近租古装汉服的地方(古色古香全是汉服)附近租古装汉服的地方(古色古香全是汉服)附近租古装汉服的地方(古色古香全是汉服)

    前段时间,曹县汉服喜提热搜,让我们看到汉服市场的巨大销售能力——竟然一年能够卖出46亿!真是万万没想到啊,现在年轻人对于汉服这么追捧呢?事实上,在传承中华文明底蕴的强大号召力下,不仅汉服制作工厂已经赚翻了,就连闲鱼这样二手交易市场的二道贩子都能一夜暴富。 有人统计,在闲鱼平台,总共有700万Coser每天在线交易,因为一手品牌汉服动不动就是几千大洋,对于学生…

    2022-01-08 • 投稿
  • 2022十大巅峰玄幻小说排行榜

    长夜余火作者:爱潜水的乌贼字数:281.25万字一本玄幻异界大陆类废土末日题材的网络小说,讲述了一个长夜漫漫的末日,一群人寻找希望的故事…….开局居然有统一婚配,这要是放在现代,估计能拯救无数单身狗吧,也是作者对未来的一种设想,真有一天到了末日废土重建可能体制也会发生大的变化吧。本书主要讲的是重建,长夜尽,黎明临,火种传承,生生不休。…

    2023-04-12
  • 想投资开店有什么好项目(小成本开店适合开什么店)

    想投资开店有什么好项目(小成本开店适合开什么店)想投资开店有什么好项目(小成本开店适合开什么店)想投资开店有什么好项目(小成本开店适合开什么店)想投资开店有什么好项目(小成本开店适合开什么店)

    想要去打工赚钱,却因为学历、技术等门槛找不到高薪工作;想要去创业赚钱,却因为手里没有资金最后放弃了……其实,在我们的日常生活中,就有着一些不需要学历门槛,也不需要太多资金支撑的赚钱小生意,因为太普遍了太平常了,我们往往容易忽视了,又或者是觉得这些小生意没那么赚钱。 其实,正是有些不起眼的小生意,老板们才赚得不亦乐乎。下面,我们就来看看…

    2021-11-10 • 投稿