一个标准的表格由<table>、<thead>、<tbody> 、< tr >、 <th>、<td>等元素组成。
表格组件的所有内容(表头和行数据)由两个 prop 构成 : columns 和 data。两者都是数组, columns用来描述每列的信息 , 井渲染在表头<thead> 内 ,可以指定某一列是否需要排序: data 是每一行的数据,由 columns 决定每一行里各列 的顺序。
index.html
可排序表格组件
index.js
var app = new Vue({
el:'#app',
data:{
columns:[
{
title:'姓名',
key:'name'
},
{
title:'年龄',
key:'age',
sortable:true
},
{
title:'出生日期',
key:'birthday',
sortable:true
},
{
title:'地址',
key:'address'
}
],
data:[
{
name:'张三',
age:18,
birthday:'2001-02-06',
address:'北京市朝阳区芍药居'
},
{
name:'李四',
age:19,
birthday:'2000-01-06',
address:'北京市海淀区西二旗'
},
{
name:'王五',
age:20,
birthday:'1999-05-08',
address:'上海市浦东新区世纪大道'
},
{
name:'赵六',
age:21,
birthday:'1998-11-02',
address:'深圳市南山区深南大道'
},
{
name:'马七',
age:24,
birthday:'1995-08-03',
address:'杭州市下沙区职教园区'
}
]
},
methods:{
handleAddData:function(){
this.data.push({
name:'钱九',
age:39,
birthday:'1989-06-08',
address:'兰州市城关区滨河路'
});
}
}
});
table.js
Vue.component('vTable',{
props:{
//用于描述每列信息,渲染在表头
columns:{
type:Array,
default:function(){
return [];
}
},
//每一行的数据,由columns决定每一行里各列的顺序
data:{
type:Array,
default:function(){
return [];
}
}
},
//数据缓存,避免操作原始数据
data:function(){
return {
currentColumns:[],
currentData:[]
}
},
render:function(h){
var _this = this;
//这里的h就是createElement
var ths = [];
this.currentColumns.forEach(function(col,index){
if(col.sortable){
ths.push(h('th',[
h('span',col.title),
h('a',{
class:{
on:col._sortType==='asc'
},
on:{
click:function(){
_this.handleSortByAsc(index)
}
}
},'↑'),
h('a',{
class:{
on:col._sortType==='desc'
},
on:{
click:function(){
_this.handleSortByDesc(index)
}
}
},'↓')
]));
}else{
ths.push(h('th',col.title));
}
});
var trs = [];
this.currentData.forEach(function(row){
var tds = [];
_this.currentColumns.forEach(function(cell){
tds.push(h('td',row[cell.key]));
});
trs.push(h('tr',tds));
});
return h('table',[
h('thead',[
h('tr',ths)
]),
h('tbody',trs)
]);
},
methods:{
/**
* map()是JavaScript数组的一个方法,根据传入的函数重新构造一个新数组。
* 排序分升序(asc)和降序(desc),而且同时只能对一列数据进行排序,与
* 其他列互斥,为了标识当前列的排序状态,在map列添加上数据时,默认给每
* 列都添加一个_sortType的字段,并赋值为normal,表示默认排序。在排序后,
* currentData每项的顺序可能都会发生变化,所以给currentColumns和currentData
* 的每个数据都添加_index字段,代表当前数据在原始数据中的索引。
*/
makeColumns:function(){
this.currentColumns = this.columns.map(function(col,index){
//添加一个字段标识当前列排序的状态,后续使用
col._sortType = 'normal';
//天剑一个字段标识当前列在数组中的索引,后续使用
col._index = index;
return col;
});
},
makeData:function(){
this.currentData = this.data.map(function(row,index){
//添加一个字段标识当前行在数组中的索引,后续使用
row._index = index;
return row;
});
},
handleSortByAsc:function(index){
var key = this.currentColumns[index].key;
this.currentColumns.forEach(function(col){
col._sortType = 'normal';
});
this.currentColumns[index]._sortType = 'asc';
this.currentData.sort(function(a,b){
return a[key]>b[key]?1:-1;
});
},
handleSortByDesc:function(index){
var key = this.currentColumns[index].key;
this.currentColumns.forEach(function(col){
col._sortType = 'normal';
});
this.currentColumns[index]._sortType ='desc';
this.currentData.sort(function(a,b){
return a[key]0){
if(sortedColumn[0]._sortType==='asc'){
this.handleSortByAsc(sortedColumn[0]._index);
}else{
this.handleSortByDesc(sortedColumn[0]._index)
}
}
}
},
mounted(){
//v-table初始化时调用
this.makeColumns();
this.makeData();
}
});
style.css
[v-cloak]{
display: none;
}
table{
width: 100%;
margin-bottom: 24px;
border-collapse: collapse;
border-spacing: 0;
empty-cells: show;
border: 1px solid #e9e9e9;
}
table th{
background: #f7f7f7;
color: #5c6b77;
font-weight: 600;
white-space: nowrap;
}
table td, table th{
padding: 8px 16px;
border: 1px solid #e9e9e9;
text-align: left;
}
table th a{
display: inline-block;
margin: 0 4px;
cursor: pointer;
}
table th a.on{
color: #3399ff;
}
table th a:hover{
color:#3399ff;
}