我司最近在搭建一款后台管理系统,使用的是Vue全家桶配合Element-ui,遇到一个问题,需要处理很多的表单,所以想到的解决方案是通过后台配置生成动态表单,这对于我来说也算是新的挑战,涉及的功能有动态表单渲染和验证,那么一起来学习一下我是如何实现的吧!
本文仅仅代表笔者自己的思路,如果您有更好的实现方式,可以在下方留下您宝贵的建议。笔者将十分感谢
开发准备 需要储备的知识点了解Element ui表单
了解Vue中的$set(target,key,value)方法
了解vant中的表单组件
本项目是基于vue-cli2.0搭建的脚手架,在这里默认大家搭建好了,谁赞成,谁反对!
静态表单数据准备后台返回的数据是这样的,这里我们拿一个json数据举例
{ "showName": "姓名", // 名称 "showValue": null, //值 "htmlElements": "输入框", // 表单类型 "fieldLength": 99, // 字段长度 "requiredOrNot": 1, // 是否必填 }然后类型的话大概有以下几种
输入框
文本域
日历控件
下拉框
单选框
复选框
我们为每一种类型生成一种组件,Test.vue组件里面
data(){ return{ fieldArray:[],// 表单字段集合 fieldObj:{}, sex:[{ // 性别 name:'男', value:"male" },{ name:"女", value:"female" } ], hobbies:[ // 爱好 { name:"吃饭", value:"吃饭" },{ name:"玩游戏", value:"玩游戏" },{ name:"打豆豆", value:"打豆豆" }, ], job:[{ // 职业 name:"医生", value:"doctor" },{ name:"老师", value:"teacher" },{ name:"司机", value:"driver" } ] } }这里准备多种日历控件是因为后续手机端使用vant组件的时候需要用到
由于vue中的数据是双向绑定的,所以只有在data里面的数据是可以实现双向绑定的,重新向data里面添加的数据无法达到双向绑定的效果,官网为我们提供了一个set方法。
作为靓仔的我,肯定很贴心的为大家准备了官网链接
这里就不过多讲解,官网比较权威,本篇博客的重点是动态表单。
Vue.set(target,propertyName/index,value)
参数:
{Object | Array} target
{string | number} propertyName/index
{any} value
返回值:设置的值。
用法:
向响应式对象中添加一个 property,并确保这个新 property 同样是响应式的,且触发视图更新。它必须用于向响应式对象上添加新 property,因为 Vue 无法探测普通的新增 property (比如 this.myObject.newProperty = 'hi')
注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象。
Element-ui表单元素 动态表单渲染这里使用axios请求本地json数据,static/json/form.json
{ "data":[ { "showName": "姓名", "showValue": null, "htmlElements": "输入框", "fieldLength": 10, "requiredOrNot": 1, "desc":"请输入姓名" }, { "showName": "描述", "showValue": null, "htmlElements": "文本域", "fieldLength": 99, "requiredOrNot": 1, "desc":"请输入描述" }, { "showName": "爱好", "showValue": null, "htmlElements": "复选框", "requiredOrNot": 1, "desc":"请选择爱好" }, { "showName": "性别", "showValue": null, "htmlElements": "单选框", "requiredOrNot": 1 }, { "showName": "出生日期", "showValue": null, "htmlElements": "日历控件", "requiredOrNot": 1, "desc":"请选择出生日期" }, { "showName": "结婚时间", "showValue": null, "htmlElements": "日历控件", "requiredOrNot": 1, "desc":"请选择结婚时间" }, { "showName": "职业", "showValue": null, "htmlElements": "下拉框", "requiredOrNot": 1, "desc":"请选择职业" } ] }Test.vue文件
<template> <div> <h2>测试动态表单</h2> <el-form :model="fieldObj" ref="ruleForm" label-width="180px"> <template v-for="(item,index) of fieldArray"> <template v-if="item.htmlElements==='输入框'"> <el-form-item :label="item.showName"> <el-input v-model="fieldObj[item.showName]" :max="item.fieldLength" :placeholder="item.desc" show-word-limit></el-input> </el-form-item> </template> <template v-if="item.htmlElements==='文本域'"> <el-form-item :label="item.showName"> <el-input type="textarea" rows="4" :placeholder="item.desc" v-model="fieldObj[item.showName]" :maxlength="item.fieldLength" show-word-limit></el-input> </el-form-item> </template> <template v-if="item.htmlElements==='日历控件'"> <el-form-item :prop="item.showName" :label="item.showName"> <el-date-picker v-model="fieldObj[item.showName]" :name="item.showName" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd" :placeholder="item.desc" ></el-date-picker> </el-form-item> </template> <template v-if="item.htmlElements==='下拉框'"> <el-form-item :label="item.showName"> <el-select v-model="fieldObj[item.showName]" :placeholder="item.describe"> <el-option v-for="items in job" :key="items.name" :label="items.name" :value="items.value"> </el-option> </el-select> </el-form-item> </template> <template v-if="item.htmlElements==='单选框'"> <el-form-item :label="item.showName"> <template v-for="(child,index) in sex"> <el-radio v-model="fieldObj[item.showName]" :label="child.value">{{child.name}}</el-radio> </template> </el-form-item> </template> <template v-if="item.htmlElements==='复选框'"> <el-form-item :label="item.showName"> <el-checkbox-group v-model="fieldObj[item.showName]"> <template v-for="(child,index) of hobbies"> <el-checkbox :label="child.name"></el-checkbox> </template> </el-checkbox-group> </el-form-item> </template> </template> </el-form> </div> </template> <script> import axios from 'axios' export default { name: "Test", data(){ return{ fieldArray:[],// 表单字段集合 fieldObj:{}, sex:[{ // 性别 name:'男', value:"male" },{ name:"女", value:"female" } ], hobbies:[ // 爱好 { name:"吃饭", value:"吃饭" },{ name:"玩游戏", value:"玩游戏" },{ name:"打豆豆", value:"打豆豆" }, ], job:[{ // 职业 name:"医生", value:"doctor" },{ name:"老师", value:"teacher" },{ name:"司机", value:"driver" } ] } }, mounted(){ this.getFieldData(); }, methods:{ getFieldData(){ // 获取动态表单数据 axios.get("../static/json/form.json").then(data=>{ let response=data.data.data; this.fieldArray=response; for(let i=0;i<response.length;i++){ let item=response[i]; if(item.htmlElements==='复选框'){ this.$set(this.fieldObj,item.showName,[]); }else { this.$set(this.fieldObj,item.showName,item.showValue); } } }) } } } </script> <style scoped> </style>现在的话,表单已经全部渲染完毕了,也实现了双向绑定,现在需要做的是如何实现动态表单验证。
官网解释:Form 组件提供了表单验证的功能,只需要通过 rules 属性传入约定的验证规则,并将 Form-Item 的 prop 属性设置为需校验的字段名即可,
prop字段
rules
model
在这里rules设置为动态的,而不是放在data里面提前写好,这里需要知道每一种类型的触发形式
输入框/文本域 trigger: 'blur'
单选框/复选框/日历控件/下拉框 trigger: 'change'
动态表单验证