Vue.js實現(xiàn)可排序的表格組件功能示例
本文實例講述了Vue.js實現(xiàn)可排序的表格組件功能。分享給大家供大家參考,具體如下:
我們基于 Vue.js 實現(xiàn)一個可根據(jù)某列進(jìn)行排序的表格組件。
一個表格包含表頭和數(shù)據(jù)兩部分內(nèi)容。因此,我們定義兩個數(shù)組,columns 表示表頭信息,在 <thread> 中渲染,并可在此指定某一列是否需要排序;data 表示數(shù)據(jù)。
html:
<div id="app" v-cloak> <v-table :data="data" :columns="columns"></v-table> <button @click="add">新增</button> </div>
把父組件中定義的 data 與 columns 傳入 v-table 組件。
js:
Vue.component('vTable', {
props: {
//表頭列名稱
columns: {
type: Array,
default: function () {
return [];
}
},
//數(shù)據(jù)
data: {
type: Array,
default: function () {
return [];
}
}
},
//為了不影響原始數(shù)據(jù),這里定義了相應(yīng)的需要操作的數(shù)據(jù)對象
data: function () {
return {
currentColumns: [],
currentData: []
}
},
//render 實現(xiàn)方式
render: function (createElement) {
var that = this;
/**
* 創(chuàng)建列樣式與表頭
*/
var ths = [];//<th> 標(biāo)簽數(shù)組
var cols = [];//<cols> 標(biāo)簽數(shù)組
this.currentColumns.forEach(function (col, index) {
if (col.width) {//創(chuàng)建列樣式
cols.push(createElement('col', {
style: {
width: col.width
}
}))
}
if (col.sortable) {
ths.push(createElement('th', [
createElement('span', col.title),
//升序
createElement('a', {
class: {
on: col.sortType === 'asc'
},
on: {
click: function () {
that.sortByAsc(index)
}
}
}, '↑'),
//降序
createElement('a', {
class: {
on: col.sortType === 'desc'
},
on: {
click: function () {
that.sortByDesc(index);
}
}
}, '↓')
]));
} else {
ths.push(createElement('th', col.title));
}
});
/**
* 創(chuàng)建內(nèi)容
*/
var trs = [];//<tr> 標(biāo)簽數(shù)組
this.currentData.forEach(function (row) {//遍歷行
var tds = [];//<td> 標(biāo)簽數(shù)組
that.currentColumns.forEach(function (cell) {//遍歷單元格
tds.push(createElement('td', row[cell.key]));
});
trs.push(createElement('tr', tds));
});
return createElement('table', [
createElement('colgroup', cols),
createElement('thead', [
createElement('tr', ths)
]),
createElement('tbody', trs)
])
},
methods: {
//初始化表頭
initColumns: function () {
this.currentColumns = this.columns.map(function (col, index) {
//新建字段,標(biāo)識當(dāng)前列排序類型;默認(rèn)為“不排序”
col.sortType = 'normal';
//新建字段,標(biāo)識當(dāng)前列在數(shù)組中的索引
col.index = index;
return col;
});
},
//初始化數(shù)據(jù)
initData: function () {
this.currentData = this.data.map(function (row, index) {
//新建字段,標(biāo)識當(dāng)前行在數(shù)組中的索引
row.index = index;
return row;
});
},
//排序
order: function (index, type) {
this.currentColumns.forEach(function (col) {
col.sortType = 'normal';
});
//設(shè)置排序類型
this.currentColumns[index].sortType = type;
//設(shè)置排序函數(shù)
var sortFunction;
var key = this.currentColumns[index].key;
switch (type) {
default://默認(rèn)為 asc 排序
case 'asc':
sortFunction = function (a, b) {
return a[key] > b[key] ? 1 : -1;
};
break;
case 'desc':
sortFunction = function (a, b) {
return a[key] < b[key] ? 1 : -1;
};
break;
}
this.currentData.sort(sortFunction);
},
//升序
sortByAsc: function (index) {
this.order(index, 'asc');
},
//降序
sortByDesc: function (index) {
this.order(index, 'desc');
}
},
watch: {
data: function () {
this.initData();
//找出排序字段
var sortedColumn = this.currentColumns.filter(function (col) {
return col.sortType !== 'normal';
});
if (sortedColumn.length > 0) {
if (sortedColumn[0].sortType === 'asc') {
this.sortByAsc(sortedColumn[0].index);
} else {
this.sortByDesc(sortedColumn[0].index);
}
}
}
},
mounted() {
this.initColumns();
this.initData();
}
});
var app = new Vue({
el: '#app',
data: {
//title 、key 與 width 必填;sortable 選填
columns: [
{
title: '名稱',
key: 'name',
width:'60%'
},
{
title: '數(shù)量',
key: 'num',
width:'20%',
sortable: true
},
{
title: '單價',
key: 'unitPrice',
width:'20%',
sortable: true
}
],
data: [
{
name: '真果粒牛奶飲品',
num: 2,
unitPrice: 59.9
},
{
name: '蘇泊爾(SUPOR)電壓力鍋 ',
num: 1,
unitPrice: 378.0
},
{
name: '樂事(Lay\'s)薯片',
num: 3,
unitPrice: 63.0
}
]
},
methods:{
add:function () {
this.data.push( {
name: '良品鋪子 休閑零食大禮包',
num: 5,
unitPrice: 59.80
});
}
}
});
為了讓排序后的 columns 與 data 不影響原始數(shù)據(jù),我們在組件的 data 中定義了相應(yīng)的當(dāng)前數(shù)據(jù)對象。因此在 method 中使用傳入的值,初始化這些數(shù)據(jù)對象,最后在 mounted() 調(diào)用這些初始化方法。
columns 中的每一項都是包含 title(列名)、key(對應(yīng) data 中的字段名)、width(寬度) 以及 sortable(是否可排序) 的對象。其中,只有 sortable 為可選項,如果設(shè)定為 true,則表示該列可點擊排序。
map() 會對數(shù)組的每一項運(yùn)行給定函數(shù),返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組。
排序分為升序與降序,因為只能對某一列進(jìn)行排序,所以是互斥操作。我們?yōu)槊恳涣行略鲆粋€ sortType ,用于標(biāo)識該列的排序類型,初始值為 normal,表示不排序。
因為排序字段可能是任意列,所以我們?yōu)槊恳涣行略鲆粋€ index,用于標(biāo)識當(dāng)前列在數(shù)組中的索引。
在 Render 函數(shù)中,首先創(chuàng)建列樣式與表頭,接著創(chuàng)建內(nèi)容。
Render 函數(shù)中的 createElement 可以簡寫為 h,這樣代碼會變得更簡潔:
render: function (h) {
var that = this;
/**
* 創(chuàng)建列樣式與表頭
*/
var ths = [];//<th> 標(biāo)簽數(shù)組
var cols = [];//<cols> 標(biāo)簽數(shù)組
this.currentColumns.forEach(function (col, index) {
if (col.width) {//創(chuàng)建列樣式
cols.push(h('col', {
style: {
width: col.width
}
}))
}
if (col.sortable) {
ths.push(h('th', [
h('span', col.title),
//升序
h('a', {
class: {
on: col.sortType === 'asc'
},
on: {
click: function () {
that.sortByAsc(index)
}
}
}, '↑'),
//降序
h('a', {
class: {
on: col.sortType === 'desc'
},
on: {
click: function () {
that.sortByDesc(index);
}
}
}, '↓')
]));
} else {
ths.push(h('th', col.title));
}
});
/**
* 創(chuàng)建內(nèi)容
*/
var trs = [];//<tr> 標(biāo)簽數(shù)組
this.currentData.forEach(function (row) {//遍歷行
var tds = [];//<td> 標(biāo)簽數(shù)組
that.currentColumns.forEach(function (cell) {//遍歷單元格
tds.push(h('td', row[cell.key]));
});
trs.push(h('tr', tds));
});
return h('table', [
h('colgroup', cols),
h('thead', [
h('tr', ths)
]),
h('tbody', trs)
])
}
創(chuàng)建內(nèi)容時,我們首先遍歷所有行,然后在循環(huán)內(nèi)部遍歷所有列,得出 <td> 與 <tr> 內(nèi)容。
創(chuàng)建表頭時,對是否排序做了相應(yīng)的處理,并綁定了相應(yīng)的點擊事件。
點擊事件定義在 methods 中,因為升序與降序邏輯大體相同,所以又封裝了一層 order() 排序函數(shù)。
order() 排序函數(shù)內(nèi)部使用了數(shù)組的 sort() 方法。sort() 方法會調(diào)用每個數(shù)組項的 toString() 方法,然后比較得到的字符串,即使數(shù)組中的每一項是數(shù)值,比較的也是字符串。這里傳入了一個比較函數(shù)作為參數(shù)。為了兼容所有瀏覽器,在比較函數(shù)中,我們返回的是 1 或者 -1。
排序之前,先把所有列的排序類型都設(shè)置為不排序,然后再更新當(dāng)前列的排序狀態(tài)。這就會對應(yīng)到 render 函數(shù)里綁定 <a> 標(biāo)簽的 class 中的 on 樣式,即當(dāng)前列排序狀態(tài)會被高亮顯示。
表格被初始化渲染之后,如果 data 發(fā)生變化,那么表格組件數(shù)據(jù)應(yīng)該也要同步更新。因此,我們在 watch 中做了數(shù)據(jù)更新以及數(shù)據(jù)重排操作。
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 {
font: bold 14px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif;
background: #CAE8EA;
color: #5c6b77;
/*設(shè)置文本粗細(xì)*/
font-weight: 600;
/*段落中的文本不進(jìn)行換行*/
white-space: nowrap;
border-top: 1px solid #C1DAD7;
}
table td, table th {
padding: 8px 16px;
text-align: left;
border-right: 1px solid #C1DAD7;
border-bottom: 1px solid #C1DAD7;
}
table th a {
/*不獨占一行的塊級元素*/
display: inline-block;
margin: 0 4px;
cursor: pointer;
}
table th a.on {
color: #3399ff;
}
table th a:hover {
color: #3399ff;
}
效果:

點擊此處查看本文示例代碼
PS:感興趣的朋友還可以使用如下在線工具測試上述代碼:
在線HTML/CSS/JavaScript前端代碼調(diào)試運(yùn)行工具:
http://tools.jb51.net/code/WebCodeRun
在線HTML/CSS/JavaScript代碼運(yùn)行工具:
http://tools.jb51.net/code/HtmlJsRun
希望本文所述對大家vue.js程序設(shè)計有所幫助。
相關(guān)文章
詳解Vue項目編譯后部署在非網(wǎng)站根目錄的解決方案
這篇文章主要介紹了Vue項目編譯后部署在非網(wǎng)站根目錄的解決方案,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
Vue.js遞歸組件實現(xiàn)組織架構(gòu)樹和選人功能
這篇文章主要介紹了Vue.js遞歸組件實現(xiàn)組織架構(gòu)樹和選人功能,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07

