iview中table组件的排序问题——关于后端多列排序的实现

最近遇到一个需求,在iview中使用table实现多列排序,主要思路就是从前端获取排序字段集合,后端动态拼接sql语句;本想着挺简单的,可实操的时候还是有些小波折的,现把实现过程记录一下:

1.ivew前端获取排序集合

iview官网中table组件的排序方法如下,在定义column时设置sortable:true属性,也可以实现数据排序,但这种排序是单页面排序,或前端排序,并未重新请求后台数据,并不符合我们的要求。table event
column evevt
在需要排序的columu中添加属性sortable:‘custom’,在table组件中监听on-sort-change事件。

    <Table stripe border @on-sort-change="sortChanged" :row-class-name="rowClass" 
    	:columns="columns2" :data="rows" :highlight-row="highlight_row" 
    	@on-selection-change="rowSelectChange" @on-row-click="onRowClick" 
    	@on-current-change="currentRowChange" :height="height" >
    </Table>
    data() {
      return {
      	//排序字段
        orderKey:[],
        // 排序类别(asc,desc)
        orderType:[],        
        //排序的字段顺序(从0开始)(设置样式时使用)
        sortIndex:[],
         // 排序类别(asc,desc,normal)(设置样式时使用)
        sortType:[],
         columns: [{
            title: 'Date',
            key: "date",      
           	sortable:'custom',  
            sortNumber: 0 ,
          },{
            title: 'Name',
            key: 'name',         
          },{
            title: 'Age',
            key: 'age',         
            sortable:'custom',      
            sortNumber: 1 ,
          },{
            title: 'Address',
            key: 'address',       
          },],
        }
     }
      sortChanged: function({ column, key, order }) {
      //order值可能为asc,desc,normal(不排序)
        let k = [];let t = [];
         k = this.orderKey
         t = this.orderType
        if(k.includes(key)){
          let i = this.printArray(k,key);
          if(order==='normal'){
            k.splice(i,1)
            t.splice(i,1)
          }else{
            t.splice(i,1,order)
          }
        }else{
          k.push(key)
          t.push(order)
        }
        this.orderKey = k
        this.orderType = t
        this.handleTheadAddClass(column,order)
        this.reload()
      },
      //返回某元素在数组中下标
      printArray(k,key){        
        for(let i=0;i

在设置iview table样式的时候有点头疼,排序是由上下两个箭头组成的,经过调试得知,点击Date升序的时候,上箭头的class由ivu-icon ivu-icon-md-arrow-dropup变为ivu-icon ivu-icon-md-arrow-dropup on,同时颜色变为蓝色选中;再次点击列Date的上箭头取消排序时,其class又由ivu-icon ivu-icon-md-arrow-dropup on变回ivu-icon ivu-icon-md-arrow-dropup,同时箭头颜色变为灰色。猜想iview是通过移除或添加箭头元素的class属性来达到控制样式的目的的,果然在iview.css中找到了与之对应的css代码.ivu-table-sort i.on{color:#2d8cf0}(ivu-table-sort为箭头父元素的class,i标签为箭头元素);现在的问题在于,当再次点击Age的升序时,Date的升序选中样式会被取消,那么如何保留样式呢,或者可不可以由我们自己重新设置样式呢,目前想到的是使用domgetElementsByClassName方法得到组件,通过动态设置id的方式自己管理排序的选中状态,如果有更好的方法请告诉我哈~
在这里插入图片描述
在设置样式handleTheadAddClass方法中,column.sortNumber为自己设置的属性,即table中第几个需要排序的列,因为需要通过找类名的方式找到对应的节点,所以一定要按照顺序写啊(从0开始)。

      // 标题行样式改变事件
      handleTheadAddClass(column,order){
        let i =[];let s = [];
        i= this.sortIndex
        s= this.sortType
        let key = column.sortNumber
        if(i.includes(key)){
          let t = this.printArray(i,key);
          s.splice(t,1,order)
        }else{
          i.push(key)
          s.push(order)
        }
        this.sortIndex = i
        this.sortType = s

        for(let a = 0; a

2.后端动态查询

为了安全,一般我们都不会把数据库字段暴露给前端,前端传来的字段和数据库字段并不是正好对应的,需要我们自己转化一下。
在我们的实体VO中,加入三个属性,注意补全get和set方法。

    /**
    * 排序标识(不允许出现数据库字段名称)
    */
    private String orderKey; 
    
    /**
     * 排序类型(升序(asc)、降序(desc))
     */
    private String orderType;

    /**
     * 排序map
     */
    private Map sortMap;

加入我们的转化类。

public class SortMapRequest implements Serializable{

    private static final long serialVersionUID = -7746939983296484048L;

    /**
     * 排序标识(不允许出现数据库字段名称)
     */
    private String orderKey;

    /**
     * 排序类型(升序(asc)、降序(desc))
     */
    private String orderType;


    public SortMapRequest(String orderKey, String orderType) {
        this.orderKey = orderKey;
        this.orderType = orderType;
    }

    public String getOrderKey() {
        return orderKey;
    }

    public void setOrderKey(String orderKey) {
        this.orderKey = orderKey;
    }

    public String getOrderType() {
        return orderType;
    }

    public void setOrderType(String orderType) {
        this.orderType = orderType;
    }

    public static Map getSort(SortMapRequest request) {
    	//使用LinkedHashMap,排序是有顺序的
        Map sortmap = new LinkedHashMap<>();
        String[] keys = request.getOrderKey().split(",");
        String[] types = request.getOrderType().split(",");
        for (int i = 0; i < keys.length; i++) {
            if ("date".equals(keys[i])) {
            	//替换成你数据库中对应的字段
                sortmap.put("Date", "Date" + types[i]);

            } else if ("indexNumber".equals(keys[i])) {
                sortmap.put("INDEX_NUMBER","INDEX_NUMBER "+ types[i]);

            } 
        }
        Map resultMap = new LinkedHashMap<>();
        for (Map.Entry entry : sortmap.entrySet()) {
            String key = entry.getKey();
            resultMap.put(key, entry.getValue());
        }
         return resultMap;
    }

}

然后在我们的service实现类里调用就可以啦,示例如下。

    	//PageBean 是一个分页对象
    public Page queryPageList(PageBean pageBean, UserVOquery){
        // 获取前台多列排序map
        Map map= SortMapRequest.getSort(
        new SortMapRequest(query.getOrderKey(), query.getOrderType()));
        if(!map.isEmpty()){
        	//将排序map设置为参数传递到mapper层			
            query.setSortMap(map);
        }
        List list = userMapper.queryPageList(pageBean,query);       
        return new Page<>(list , pageBean);
    }

然后是mapper的XML文件的写法。

 

好,到此多列排序就完成了,可能还存在一些问题,再慢慢改进吧!

你可能感兴趣的:(vue)