欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Vue 利用后端的数据字典和Map对象实现表格列字段动态转义的处理方案

程序员文章站 2022-06-19 12:19:20
利用后端的数据字典,可以提高前端系统的灵活性;利用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);
    },
  }

  注意事项:

  1. 由于数据是动态获取的,但vue 无法监听动态新增的属性的变化,需要用 $set 来为这些属性赋值。否则选择框的选择选项后,当前值的显示不会改变。

        //用户类型选择
        selectusertype(item){
          console.log(item);
          this.$set(this.formdata.queryinfo,'usertype',parseint(item.itemkey));
          this.$set(this.formdata,'usertypelabel',item.itemvalue);
        },
    
  2. 为了使得选择框的选择能够生效,

    <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。

  3. 在data部分,定义了用户类型的列表和字典对象。其中用户类型列表用于选择框,字典用于表格数据列字段转义。其中,用户类型列表设置了初始项,表示全部类型。(也可以约定由后端的系统参数表来统一定义,这样前端无需设置初始项)。

          //用户类型参照表,构造初始数据项
          usertypelist  : [
            {
              itemkey   : "0",
              itemvalue : "所有类型"
            }
          ],
    
          //用户类型字典
          usertypemap : new map(),
    
  4. 系统参数的获取方法,一般在页面加载时获取:

      created() {
        // ==========================================
        // 获取需要的系统参数,注意:getparameterclass方法是异步加载数据的。
        // 如需要打印观察,需要通过watch来处理
    
        // 获取用户类型的参数类别
        this.commonfuncs.getparameterclass(this,"user_type","usertypelist","usertypemap");
      },
    

    调用公共方法getparameterclass,可以一次性获取某个参数类别的列表和字典数据,允许获取某一种类型数据,只需将另一个参数设为空字符串即可。

    列表和字典的参数值,必须在data中声明的属性名,并且类型要匹配。

    从代码量看,获取系统参数的调用是相当简洁的。

  5. 在系统参数获取成功后的处理,一般在watch中实现。

      watch:  {
        usertypelist  : {
          handler(newvalue, oldvalue){
            //获取数据后,设置选择框的初始值;
            this.$set(this.formdata,'usertypelabel',this.usertypelist[0].itemvalue);
          },
          immediate: true
        },  
      }, 
    

    监视到usertypelist数据加载完毕后,设置用户类型选择框的初始选择项。

2.5、效果图

  运行vue,在浏览器输入相应url,页面显示如下:

Vue 利用后端的数据字典和Map对象实现表格列字段动态转义的处理方案

  可以看到列表中用户类型数据列已经转义显示。

2.6、其它

  如果数据字典不是由后台提供,而是前端固化,则只需在data中声明usertypemap为字典类型,然后在created事件中,完成初始化即可。

  这种情况下,数据列转义仍然有效。