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事件中,完成初始化即可。
这种情况下,数据列转义仍然有效。