Vue 利用后端的数据字典和Map对象实现表格列字段动态转义的处理方案
1、前言
Vue中,使用el-table组件,经常遇到列字段转义的问题。常规处理方法有以下两种:
- 方法1:在模板中使用v-if,直接转义。如:
<el-table-column label="是否学员" prop="isStudent" min-width="7%"> <template slot-scope="scope"> <span v-if="scope.row.participantType == 0">N</span> <span v-if="scope.row.participantType == 1">Y</span> </template> </el-table-column>
- 方法2:使用formatter,进行转义处理,如:
在模板中指明使用格式转换器:
<el-table-column label="证件类型" prop="idType" :formatter="idFormatter" min-width="10%"></el-table-column>
在Javascript中,实现指定的格式转换器:
data() { return { // 证件类型列表 idTypeList: [ {idType:1,idTypeName:"身份证"}, {idType:2,idTypeName:"社保卡"}, {idType:3,idTypeName:"驾驶证"}, {idType:4,idTypeName:"护照"}, {idType:5,idTypeName:"临时身份证"}, {idType:6,idTypeName:"工作证"} ], //其它属性 //... } }, methods: { // 证件类型字段翻译 idFormatter(row, column) { var value = ""; for (var i = 0; i < this.idTypeList.length; i++){ var item = idTypeList[i]; if (row.idType == item.idType) { value = item.idTypeName; break; } } return value; }, }
这两种处理方法都有效,但感觉不是很好。
方法1的问题,是需要枚举各种可能性,如果枚举项很多,代码固化,书写是个体力活,且代码很不简洁。另外,灵活性不高,如果后端对该字段增加枚举项,前端也需要修改。
方法2的问题,如果需要字段转义的列较多时,需要定义较多的格式转换器方法。
因此,推荐使用下面的方案。
2、动态字段转义处理方案
2.1、后端使用系统参数表并提供查询接口
首先,后端对字段的枚举类型,均使用系统参数表来存储,这样,前后端统一使用同一份数据字典。参见之前的文章:《使用系统参数表,提升系统的灵活性 》。
然后,后端提供相应的接口,供前端获取指定类别的参数项(枚举项)列表。接口定义如下:
Path: /sysParam/getParameterClass Method: POST 接口描述: 请求参数: Headers 参数名称 参数值 是否必须 示例 备注 Content-Type application/json 是 Authorization token 是 token值 Body 名称 类型 是否必须 默认值 备注 其他信息 classKey string 必须 参数类别key 返回数据: 名称 类型 是否必须 默认值 备注 其他信息 data object [] 非必须 返回数据 item 类型: object ├─ SysParameter类型 各字段,略 code integer 必须 返回码 message string 必须 提示信息 additional object 非必须 附加信息,Additional类型,略
2.2、前端获取系统参数的常规方法
页面中获取系统参数的常规处理方法,如下:
data() { return { // 证件类型列表 idTypeList: [], //其它属性 //... } }, created() { this.getIdTypeList(); }, methods: { // 证件类型字段翻译 idFormatter(row, column) { var value = ""; for (var i = 0; i < this.idTypeList.length; i++){ var item = idTypeList[i]; if (row.idType == item.idType) { value = item.idTypeName; break; } } return value; }, // 获取证件类型列表数据 getIdTypeList() { let _this = this; this.instance.getParameterClass(this.$baseUrl,{"classKey":"id_type"}).then((response) => { _this.idTypeList = response.data.data; }); }, }
api/index.js中定义instance的接口:
//获取类别信息列表 getParameterClass (baseurl, data) { var url = baseurl + '/sysParam/getParameterClass'; return instance.post(url, data); },
现在的问题,如果获取每个参数类型,都要用一个方法来实现,显得太繁琐,代码不优雅。另外,列字段转义还是使用了格式转换器,因为列表数据只能使用遍历。
2.3、前端开发公共方法来获取系统参数
现在的方案,字段转义的数据字典由后端定义,这样一来,前端各个页面将会大量调用获取系统参数的接口。因此有必要开发公共方法来获取系统参数。
参数类别的数据,页面需要两种类型的数据:
- 列表类型,用于选择框,如查询条件,此时往往需要在列表中增加一项类似“全部类型”的选项,表示忽略此条件。
- 字典类型,用于表格列字段转义。
在/src/common/commonFuncs.js中,实现获取系统参数的方法,代码如下:
/** * 获取参数类别信息列表及字典 * @param {容器对象} parent * @param {参数类别key} classKey * @param {列表的属性名} listObjPropName * @param {字典的属性名} mapObjPropName * @param {字段数据类型} fieldDatatype */ getParameterClass(parent, classKey, listObjPropName, mapObjPropName, fieldDatatype="int"){ parent.instance.getParameterClass( parent.$baseUrl, {"classKey" : classKey} ).then(res => { //console.log(res.data); if (res.data.code == parent.global.SucessRequstCode){ //如果查询成功 //console.log(res.data.data); if (listObjPropName != undefined && listObjPropName != ""){ //需要输出列表数据 for(var i = 0; i < res.data.data.length; i++){ var item = res.data.data[i]; //往后添加数据,不破坏列表原有数据 parent[listObjPropName].push(item); } } if(mapObjPropName != undefined && mapObjPropName != ""){ //需要输出字典数据 //字典的key要匹配字段类型,由于itemKey为类型为字符串,而字段数据类型一般为整型(枚举值) //可能需要进行类型转换 //遍历列表数据 for(var i = 0; i < res.data.data.length; i++){ var item = res.data.data[i]; var mapKey; if (fieldDatatype == "int"){ //字符串转int mapKey = parseInt(item.itemKey); }else{ mapKey =item.itemKey; } //加入字典 parent[mapObjPropName].set(mapKey,item); } } }else{ alert(res.data.message); } }).catch(error => { alert('查询系统参数失败!'); console.log(error); }); }
2.4、Vue文件中获取系统参数的用法
样例Vue文件,模板代码如下:
<template> <div id="contentwrapper"> <el-form ref="form" :model="formData" label-width="80px"><el-card> <el-row> <!--占整行--> <el-col :span="24"> <h5 class="heading" align=left>用户管理 / 用户管理</h5> <!-- 分隔线 --> <el-divider></el-divider> </el-col> </el-row> <el-row> <el-col align="left" :span="6"> <el-button type="primary" size="small" @click="addUser"> <i class="el-icon-circle-plus"></i>添加用户 </el-button> </el-col> <!-- 查询条件 --> <el-col align="left" :span="12"> <el-form-item label="用户类型:" label-width="100px"> <el-select v-model="formData.userTypeLabel" size="small" @change="selectUserType"> <el-option v-for="(item,index) in userTypeList" :key="index" :label="item.itemValue" :value="item" /> </el-select> </el-form-item> </el-col> <el-col align="right" :span="6"> <el-button type="primary" size="small" @click="queryUsers"> <i class="el-icon-search"></i>查询 </el-button> </el-col> </el-row> <!-- 用户列表数据 --> <el-table :data="userInfoList" border stripe :row-style="{height:'30px'}" :cell-style="{padding:'0px'}" style="font-size: 10px"> <el-table-column label="用户ID" prop="userId"></el-table-column> <el-table-column label="用户类型" width="80px" prop="userType"> <template slot-scope="scope"> <span>{{userTypeMap.get(scope.row.userType).itemValue}}</span> </template> </el-table-column> <el-table-column label="登录名" prop="loginName"></el-table-column> <el-table-column label="真实名称" prop="userName"></el-table-column> <el-table-column label="手机号码" prop="phoneNumber" width="80px"></el-table-column> <el-table-column label="EMail" prop="email" width="80px"></el-table-column> <el-table-column label="操作" width="60px"> <template slot-scope="scope"> <el-tooltip class="item" effect="dark" content="编辑" placement="left-start"> <el-button size="mini" type="primary" icon="el-icon-edit" circle @click="editUser(scope.row)"></el-button> </el-tooltip> </template> </el-table-column> </el-table> </el-card> </el-form> </div> </template>
模板代码中,有一个用户类型的选择框,还有表格中对用户类型数据列进行转义处理。注意数据列转义处理的处理代码:
<el-table-column label="用户类型" width="80px" prop="userType"> <template slot-scope="scope"> <span>{{userTypeMap.get(scope.row.userType).itemValue}}</span> </template> </el-table-column>
这个代码相当简洁。
下面是javascript中与系统参数获取与设置相关的代码:
data() { return { formData : { //查询信息 queryInfo:{ userType : 0, deleteFlag: 0, pagenum : 1, pagesize : 10 }, //用户类型选择框当前选择项的显示值 userTypeLabel : "所有类型" }, //用户类型参照表,构造初始数据项 userTypeList : [ { itemKey : "0", itemValue : "所有类型" } ], //用户类型字典 userTypeMap : new Map(), //查询到的用户信息列表 userInfoList:[], //新增编辑对话框可见标记 editVisible:false, show:false } }, created() { // ========================================== // 获取需要的系统参数,注意:getParameterClass方法是异步加载数据的。 // 如需要打印观察,需要通过watch来处理 // 获取用户类型的参数类别 this.commonFuncs.getParameterClass(this,"user_type","userTypeList","userTypeMap"); }, watch: { userTypeList : { handler(newValue, oldValue){ //获取数据后,设置选择框的初始值; this.$set(this.formData,'userTypeLabel',this.userTypeList[0].itemValue); }, immediate: true }, userTypeMap : { handler(newValue, oldValue){ console.log(newValue); }, immediate: true } }, methods: { //查询用户信息列表 queryUsers(){ let _this = this; this.instance.queryUsers( this.$baseUrl,this.formData.queryInfo ).then(res => { console.log(res.data); if (res.data.code == this.global.SucessRequstCode){ //如果查询成功 _this.formData.pageInfo.total = res.data.data.length; _this.userInfoList = res.data.data; }else{ alert(res.data.message); } }).catch(error => { alert('查询失败!'); console.log(error); }); }, //用户类型选择 selectUserType(item){ console.log(item); this.$set(this.formData.queryInfo,'userType',parseInt(item.itemKey)); this.$set(this.formData,'userTypeLabel',item.itemValue); }, }
注意事项:
由于数据是动态获取的,但vue 无法监听动态新增的属性的变化,需要用 $set 来为这些属性赋值。否则选择框的选择选项后,当前值的显示不会改变。
//用户类型选择 selectUserType(item){ console.log(item); this.$set(this.formData.queryInfo,'userType',parseInt(item.itemKey)); this.$set(this.formData,'userTypeLabel',item.itemValue); },
为了使得选择框的选择能够生效,
<el-form ref="form" :model="formData" label-width="80px">
的model设置必须包含选择框的当前选择项的显示值,即:
<el-form-item label="用户类型:" label-width="100px"> <el-select v-model="formData.userTypeLabel" size="small" @change="selectUserType"> <el-option v-for="(item,index) in userTypeList" :key="index" :label="item.itemValue" :value="item" /> </el-select> </el-form-item>
el-select的v-model即userTypeLabel必须在form的model中,也就是说formData必须包含userTypeLabel。
在data部分,定义了用户类型的列表和字典对象。其中用户类型列表用于选择框,字典用于表格数据列字段转义。其中,用户类型列表设置了初始项,表示全部类型。(也可以约定由后端的系统参数表来统一定义,这样前端无需设置初始项)。
//用户类型参照表,构造初始数据项 userTypeList : [ { itemKey : "0", itemValue : "所有类型" } ], //用户类型字典 userTypeMap : new Map(),
系统参数的获取方法,一般在页面加载时获取:
created() { // ========================================== // 获取需要的系统参数,注意:getParameterClass方法是异步加载数据的。 // 如需要打印观察,需要通过watch来处理 // 获取用户类型的参数类别 this.commonFuncs.getParameterClass(this,"user_type","userTypeList","userTypeMap"); },
调用公共方法getParameterClass,可以一次性获取某个参数类别的列表和字典数据,允许获取某一种类型数据,只需将另一个参数设为空字符串即可。
列表和字典的参数值,必须在data中声明的属性名,并且类型要匹配。
从代码量看,获取系统参数的调用是相当简洁的。
在系统参数获取成功后的处理,一般在watch中实现。
watch: { userTypeList : { handler(newValue, oldValue){ //获取数据后,设置选择框的初始值; this.$set(this.formData,'userTypeLabel',this.userTypeList[0].itemValue); }, immediate: true }, },
监视到userTypeList数据加载完毕后,设置用户类型选择框的初始选择项。
2.5、效果图
运行Vue,在浏览器输入相应url,页面显示如下:
可以看到列表中用户类型数据列已经转义显示。
2.6、其它
如果数据字典不是由后台提供,而是前端固化,则只需在data中声明userTypeMap为字典类型,然后在created事件中,完成初始化即可。
这种情况下,数据列转义仍然有效。
- VUE+SSM 以VUE做项目前端,SSM做后端框架,难点在于数据的传输处理,下面我记录一下一个简单的登录退出功能的实现,如果有缺陷还请大佬指出,个人菜鸟 一个,正在学习当中,以此记录一下自己的学习
- vue.js前端开发,利用echarts组件实现动态数据展示
- vue+vue-router+vuex,利用vue-router2.2.0新增特性addRoutes实现路由动态加载,菜单动态加载,运用于后台管理系统,路由数据取自数据库
- 循序渐进VUE+Element 前端应用开发(5)--- 表格列表页面的查询,列表展示和字段转义处理
- JS实现动态生成表格并提交表格数据向后端
- 利用vue-router的动态路由和路由传值实现同一模板渲染不同数据
- 利用 Map 集合的 containsKey 方法,实现对象数组的去重以及重复对象的字段值累加
- 自己在项目中的学习总结:利用工厂模式+反射机制+缓存机制,实现动态创建不同的数据层对象接口
- Vue.js实现简单动态数据处理
- 【前端知识点】前后端关于post请求中,对body的不同数据格式的解决处理方案实现
- ## MyBatis持久层框架,实现数据访问,抽象方法多参数的处理,关于别名,MyBatis中的动态SQL,resultMap
- 如何利用AOP将对象数据字典字段code转换name输出前端展示
- JS实现动态生成表格并提交表格数据向后端
- JS实现动态生成表格并提交表格数据向后端
- 利用 Vue 和 element 的实现table增、删、改表格数据的模糊匹配搜索
- vue+element实现从后台获取数据动态形成表格
- mybaits(查询与别名、日志框架显示sql语句、对象属性和数据库表字段不匹配resultMap使用、mysql数据查询分页、执行sql和存储过程、动态SQL语句)
- vue.js 利用SocketCluster实现动态添加数据及排序
- 利用autocomplete.js实现仿百度搜索效果(ajax动态获取后端[C#]数据)
- Vue实现表格中对数据进行转换、处理的方法