最近遇到一个需求,在iview中使用table实现多列排序,主要思路就是从前端获取排序字段集合,后端动态拼接sql语句;本想着挺简单的,可实操的时候还是有些小波折的,现把实现过程记录一下:
在iview
官网中table
组件的排序方法如下,在定义column
时设置sortable:true
属性,也可以实现数据排序,但这种排序是单页面排序,或前端排序,并未重新请求后台数据,并不符合我们的要求。
在需要排序的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的升序选中样式会被取消,那么如何保留样式呢,或者可不可以由我们自己重新设置样式呢,目前想到的是使用dom
的getElementsByClassName
方法得到组件,通过动态设置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
为了安全,一般我们都不会把数据库字段暴露给前端,前端传来的字段和数据库字段并不是正好对应的,需要我们自己转化一下。
在我们的实体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文件的写法。
好,到此多列排序就完成了,可能还存在一些问题,再慢慢改进吧!