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)

相关推荐

  • 基金收益计算器公式(怎么计算基金的本金和收益)

    很多买了基金的朋友,每天都会查看自己的收益;一般包括昨日收益,也就是昨天一天涨了还是跌了;持有收益,正在持有的基金一共赚了多少钱;还有累计收益,过去买过的所有基金,包括已经赎回的和正在持有基金加在一起的收益。   图片仅作示意 这些收益都是怎么计算的?小夏今天来帮大家讲讲~ 01 基金的每日收益和持有收益怎么算? 我们每天在基金公司和第三方平台看到…

    2021-11-19
  • 中元节鬼会来家里,中元节是鬼的节日吗

    今天是中元节,老家老人说中元节这天是鬼的节日,阴间放假一天,众鬼魂到晚上就就各回各家,看看自己的子孙后代,所以这一天都是要待在自己家里,不能在丈母娘家里过夜,否则自家鬼魂会认错人。真有这事吗?相信科学的,肯定不会相信,但在我们老家农村是相信的,并一直传承下来。 从我记事起,中元节都是一个特别的节日,中元节前插秧已经完成了,山上满山的捻子一到过了中元节的晚上,…

    2023-06-03
  • 未来10大暴利行业,未来最挣钱的十大行业排行榜

    不论你是正在上学的学生,还是打算转行的毕业生,亦或者考虑创业的中年人,这六个行业都值得你好好投入精力去钻研。 因为这些都是未来最赚钱的行业。 一直以来,我们都在强调一件事情,就是一定要做顺应趋势的人。 无论是08年加入房地产,还是13年开始搞淘宝,还是15年开始做公众号,还是17年开始的短视频风潮,这一波波趋势,肉眼可见地让许多无背景,无后台的年轻人走上了逆…

    2022-04-22 创业项目
  • 搜索竞价优化方法(搜索竞价营销优化策略)

    一、以网站为出发点 网站结构 一个好的网站结构是后期网站持续优化的基础,所以网站的维度和结构要清晰且有条理。 网站的结构搭建有五个维度:产品维度、时间维度、平台维度、地区维度、购买阶段维度。确定维度以后根据访客不同的搜索需求和关键词词根的性质来细分单元。例如价格、行业等等。 二、关键词 关键词的覆盖要全面 尽量把关键词全面覆盖到访客的需求。这个全面性不以数量…

    2021-12-27
  • erp系统操作流程图(仓库erp一般要学多久才会)

    有一朋友,原先在企业里做制造经理,积累了很多年的制造经验与人脉,想着自己出来整一个加工厂,主要业务就是来料加工;特意打电话给我,咨询用友的U8ERP业务流程应该怎样搭建?朋友在原企业用U8产品用习惯了,不想换其他软件,所以特意帮他梳理了一下这个流程,并分享给大家一起学习。 一、总体业务流程图 二、基础资料处理 1、建立客户产品BOM清单 A为代工件,存货属性…

    2023-05-25
  • 移动最优惠流量套餐(优惠的移动流量套餐)

    现在的手机性能非常好,大家天天会用来上网处理各种事情,这些年我国的上网用户量非常多,尤其是现在网络在很多地方普及,大家日常需要用到的上网设备比较多,每当我们在固定的使用往往都会安装宽带了,用起来就很好用了,但是现在还是有很多的地方没有可用的无线网络,我们就只能用手机流量卡来上网了,这样一个月下来也是需要不少的流量才能够用了。 我国的通信商有中国移动、联通、电…

    2023-05-24 投稿
  • 十大元帅军事能力排名(中国十大元帅排名)

    众所周知,1955年大授衔时,十大元帅的排名是朱、彭、林、刘、贺、陈、罗、徐、聂、叶。关于这个排序的确定,有各种各样的说法,其中,职务、资历、战功及“山头”平衡,是决定授衔及排序的四大要素。仔细分析一下,林总排名第三,实际上在红军改编为八路军、新四军时,就已经基本定调。为什么这样说呢?   首先简要回顾和比较一下资历问题。 林总参加了南昌起义,在参…

    2022-01-01 投稿
  • 服务器配置单,服务器配置单用户怎么设置

    《服务器配置单:从入门到精通》 一、服务器配置单的基本构成服务器配置单可能就像是一台服务器的“蓝图”,它详细地记录了服务器的各种硬件和软件配置信息。一般来说,它会包含服务器的型号、处理器规格、内存大小、硬盘类型和容量、网络接口等基本信息。也许就像建造一座房子,这些基本构成就像是房子的地基和框架,决定了服务器的基本性能和功能。 比如说,服务器的型号就像是房子的…

    投稿 2025-10-10
  • 包子变白的诀窍(在家蒸酱肉馅的包子)

    今天给大家分享怎样在家蒸酱肉馅的包子,做法简单,家里大人小孩都喜欢吃。 下面来跟我看下制作方法吧 1、先从和面开始介绍,每次分享做面食都是从最基本的和面开始,往和面盆里倒入中筋面粉,温水碗里加入酵母粉搅匀化开,平均一斤面粉里大约加3-5g的酵母粉。一般在家里蒸馒头、包子、饺子、面条,用的都是中筋面粉,而高筋面粉是做面包用的,低筋面粉是做蛋糕用的。很多人问做面…

    2022-05-14 投稿
  • 有没有想在家做兼职的(在家能做的兼职正规)

    现在好多人空闲时候不知道做些什么,无所事事,总想找一些兼职来做,赚点零花钱,有哪些兼职不累不用出门,手机电脑就能做的呢?我给大家找了一些,仅供参考! 一、发布文章、微头条、视频可获得收益。 只要你文笔好,思路清晰,创作能力强,在展天博客赚钱肯定是一个不错的选择,不限地点、不限时间,只要你有空就可以做。 发布文章就像写作文,只要文采好,阅读浏览的人肯定不少。微…

    2022-01-21 投稿
  • 唐嫣超级话题新浪微博(唐嫣罗晋粉丝团地盘微博)

    近日,赵丽颖和冯绍峰突然官宣了离婚的消息,对于很多网友来说,这个消息都太突然了,而且大家毫无准备,之前也毫无征兆。所以说,面对这样的消息后,大家开始思考,85花的婚姻是怎么回事呢?杨幂和刘恺威也离婚了,赵丽颖和冯绍峰也离婚了,而杨颖和黄晓明已经不止一次被传出离婚的传言了,只是一直都没有回应而已。所以说,85花的婚姻情况好像不容乐观。但是,也有很多人表示,那都…

    2022-01-02 投稿
  • 2021年灵活就业社保新规 北京,北京灵活就业人员社保2021年缴费标准

    灵活就业人员是一个非常庞大的群体。人社部数据显示2020年我国灵活就业人数已经超过了2亿人。他们通过不固定的工作养活自己,等他们年老体衰以后怎么办?因此参加养老保险才是最好的选择。 大多数灵活就业人员收入水平不高,在参加养老保险的时候,都会选择最低基数缴费。如果我们按照最低基数缴费15年,养老金能领多少钱呢?让我们算一算。 养老保险缴费钱数是多少? 灵活就业…

    2022-03-21