Vue.js實(shí)現(xiàn)可排序的表格組件功能示例
本文實(shí)例講述了Vue.js實(shí)現(xiàn)可排序的表格組件功能。分享給大家供大家參考,具體如下:
我們基于 Vue.js 實(shí)現(xiàn)一個(gè)可根據(jù)某列進(jìn)行排序的表格組件。
一個(gè)表格包含表頭和數(shù)據(jù)兩部分內(nèi)容。因此,我們定義兩個(gè)數(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ù)對(duì)象 data: function () { return { currentColumns: [], currentData: [] } }, //render 實(shí)現(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)識(shí)當(dāng)前列排序類(lèi)型;默認(rèn)為“不排序” col.sortType = 'normal'; //新建字段,標(biāo)識(shí)當(dāng)前列在數(shù)組中的索引 col.index = index; return col; }); }, //初始化數(shù)據(jù) initData: function () { this.currentData = this.data.map(function (row, index) { //新建字段,標(biāo)識(shí)當(dāng)前行在數(shù)組中的索引 row.index = index; return row; }); }, //排序 order: function (index, type) { this.currentColumns.forEach(function (col) { col.sortType = 'normal'; }); //設(shè)置排序類(lèi)型 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: '單價(jià)', key: 'unitPrice', width:'20%', sortable: true } ], data: [ { name: '真果粒牛奶飲品', num: 2, unitPrice: 59.9 }, { name: '蘇泊爾(SUPOR)電壓力鍋 ', num: 1, unitPrice: 378.0 }, { name: '樂(lè)事(Lay\'s)薯片', num: 3, unitPrice: 63.0 } ] }, methods:{ add:function () { this.data.push( { name: '良品鋪?zhàn)?休閑零食大禮包', num: 5, unitPrice: 59.80 }); } } });
為了讓排序后的 columns 與 data 不影響原始數(shù)據(jù),我們?cè)诮M件的 data 中定義了相應(yīng)的當(dāng)前數(shù)據(jù)對(duì)象。因此在 method 中使用傳入的值,初始化這些數(shù)據(jù)對(duì)象,最后在 mounted() 調(diào)用這些初始化方法。
columns 中的每一項(xiàng)都是包含 title(列名)、key(對(duì)應(yīng) data 中的字段名)、width(寬度) 以及 sortable(是否可排序) 的對(duì)象。其中,只有 sortable 為可選項(xiàng),如果設(shè)定為 true,則表示該列可點(diǎn)擊排序。
map() 會(huì)對(duì)數(shù)組的每一項(xiàng)運(yùn)行給定函數(shù),返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組。
排序分為升序與降序,因?yàn)橹荒軐?duì)某一列進(jìn)行排序,所以是互斥操作。我們?yōu)槊恳涣行略鲆粋€(gè) sortType ,用于標(biāo)識(shí)該列的排序類(lèi)型,初始值為 normal,表示不排序。
因?yàn)榕判蜃侄慰赡苁侨我饬?,所以我們?yōu)槊恳涣行略鲆粋€(gè) index,用于標(biāo)識(shí)當(dāng)前列在數(shù)組中的索引。
在 Render 函數(shù)中,首先創(chuàng)建列樣式與表頭,接著創(chuàng)建內(nèi)容。
Render 函數(shù)中的 createElement 可以簡(jiǎn)寫(xiě)為 h,這樣代碼會(huì)變得更簡(jiǎn)潔:
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)容時(shí),我們首先遍歷所有行,然后在循環(huán)內(nèi)部遍歷所有列,得出 <td> 與 <tr> 內(nèi)容。
創(chuàng)建表頭時(shí),對(duì)是否排序做了相應(yīng)的處理,并綁定了相應(yīng)的點(diǎn)擊事件。
點(diǎn)擊事件定義在 methods 中,因?yàn)樯蚺c降序邏輯大體相同,所以又封裝了一層 order() 排序函數(shù)。
order() 排序函數(shù)內(nèi)部使用了數(shù)組的 sort() 方法。sort() 方法會(huì)調(diào)用每個(gè)數(shù)組項(xiàng)的 toString() 方法,然后比較得到的字符串,即使數(shù)組中的每一項(xiàng)是數(shù)值,比較的也是字符串。這里傳入了一個(gè)比較函數(shù)作為參數(shù)。為了兼容所有瀏覽器,在比較函數(shù)中,我們返回的是 1 或者 -1。
排序之前,先把所有列的排序類(lèi)型都設(shè)置為不排序,然后再更新當(dāng)前列的排序狀態(tài)。這就會(huì)對(duì)應(yīng)到 render 函數(shù)里綁定 <a> 標(biāo)簽的 class 中的 on 樣式,即當(dāng)前列排序狀態(tài)會(huì)被高亮顯示。
表格被初始化渲染之后,如果 data 發(fā)生變化,那么表格組件數(shù)據(jù)應(yīng)該也要同步更新。因此,我們?cè)?watch 中做了數(shù)據(jù)更新以及數(shù)據(jù)重排操作。
css:
[v-cloak] { display: none; } table { width: 100%; margin-bottom: 24px; /*合并邊框模型*/ border-collapse: collapse; border-spacing: 0; /*在空單元格周?chē)L制邊框*/ 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 { /*不獨(dú)占一行的塊級(jí)元素*/ display: inline-block; margin: 0 4px; cursor: pointer; } table th a.on { color: #3399ff; } table th a:hover { color: #3399ff; }
效果:
點(diǎn)擊此處查看本文示例代碼
PS:感興趣的朋友還可以使用如下在線工具測(cè)試上述代碼:
在線HTML/CSS/JavaScript前端代碼調(diào)試運(yùn)行工具:
http://tools.jb51.net/code/WebCodeRun
在線HTML/CSS/JavaScript代碼運(yùn)行工具:
http://tools.jb51.net/code/HtmlJsRun
希望本文所述對(duì)大家vue.js程序設(shè)計(jì)有所幫助。
相關(guān)文章
vue框架制作購(gòu)物車(chē)小球動(dòng)畫(huà)效果實(shí)例代碼
最近在學(xué)習(xí)前端制作了一個(gè)購(gòu)物車(chē)小球的動(dòng)畫(huà)效果,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2019-09-09詳解Vue項(xiàng)目編譯后部署在非網(wǎng)站根目錄的解決方案
這篇文章主要介紹了Vue項(xiàng)目編譯后部署在非網(wǎng)站根目錄的解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04Vue.js遞歸組件實(shí)現(xiàn)組織架構(gòu)樹(shù)和選人功能
這篇文章主要介紹了Vue.js遞歸組件實(shí)現(xiàn)組織架構(gòu)樹(shù)和選人功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07