vue实现表格组件,带分页
生活随笔
收集整理的這篇文章主要介紹了
vue实现表格组件,带分页
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
?最近因?yàn)轫?xiàng)目需要,利用vue開(kāi)發(fā)了一套利于擴(kuò)展的表格組件,可選擇分頁(yè)展示,帶有排序功能支持,支持自定義操作按鈕與class以及自定義render渲染。效果如下:
點(diǎn)擊在線體驗(yàn)
使用簡(jiǎn)單:
html:
vue實(shí)例中傳入基本的列信息:
?完整代碼:
<html><head><script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><script src="http://code.jquery.com/jquery-1.4.1.min.js"></script><style>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; font-weight: 600; 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;}.row{display: flex;-ms-flex-wrap: wrap; flex-wrap: wrap; margin-right: -12px; margin-left: -12px;}.row .col-4{ -webkit-box-flex: 0; -ms-flex: 0 0 33.33333%; flex: 0 0 33.33333%; max-width: 20%; position: relative; width: 100%; padding-right: 12px; padding-left: 12px;}.pagination{list-style: none;display: -webkit-box;display: -ms-flexbox;border-radius: .25rem;}.col-4{-webkit-box-flex: 0;flex: 0 0 33.33333%;max-width: 20%;}.pagination-sm{margin: 0;}button{outline: none;}.pagination-sm .page-link{padding: .25rem .5rem;font-size: .74375rem;line-height: 1.5;margin: 0;}.pagination-sm .active .page-link{color: red;}.btn-confirm {position: absolute; top: 50%; left: 70%; transform: translate(-50%, -50%); width: 80px; height: 30px; line-height: 20px; text-align: center; color: #fff;text-transform: uppercase; text-decoration: none; font-family: sans-serif; box-sizing: border-box; background: linear-gradient(90deg, #03a9f4, #f441a5, #ffeb3b, #03a9f4); background-size: 400%; border-radius: 60px; z-index: 1; }.btn-confirm:hover { animation: animate 8s linear infinite; } @keyframes animate { 0% { background-position: 0%; } 100% { background-position: 400%; } } .btn-confirm::before { content: ''; position: absolute; top: -5px; left: -5px; right: -5px; bottom: -5px; z-index: -1; background: linear-gradient(90deg, #03a9f4, #f441a5, #ffeb3b, #03a9f4); background-size: 400%; border-radius: 40px; opacity: 0; transition: 0.5s; }.btn-confirm:hover::before { filter: blur(20px); opacity: 1; animation: animate 8s linear infinite; } </style></head><body><div id="app"><tt-table :datas="datas" :columns="columns" pageSize=2 :rows="rows"></tt-table></div><script> /**分頁(yè)組件嵌入到表格中*/ Vue.component('page-split', {props: {totalRows: {required: true,type: Number},pageSize: {type: Number,default: 8},pageNumAmount: {type: Number,default: 3},pageNum: {type: Number,default: 1}},model: {prop: 'pageNum',event: 'switch-page'},data: function data() {return {totalPage: 0,inputPage: '',showPageList: []};},created: function() {this.calShowPageNums();},watch: {totalRows: function totalRows() {this.calShowPageNums();}},methods: {invokeAjaxMethod: function(){this.$emit('switch-page', this.pageNum);this.calShowPageNums();},toSpecialPage: function toSpecialPage() {if (!/^\d{1,10}$/.test(this.inputPage)) {this.inputPage = '';return false;}if (this.inputPage > this.totalPage || this.inputPage < 1) {this.inputPage = '';return false;}this.pageNum = this.inputPage;this.invokeAjaxMethod();},prePage: function prePage() {if (this.pageNum < 2) {return false;}this.pageNum--;this.invokeAjaxMethod();},goPage: function goPage(pageNo) {this.pageNum = pageNo;this.invokeAjaxMethod();},nextPage: function nextPage() {if (this.pageNum == this.totalPage) {return false;}this.pageNum++;this.invokeAjaxMethod();},//計(jì)算應(yīng)該展示出的頁(yè)號(hào)calShowPageNums: function calShowPageNums() {this.totalPage = this.getNumMultiple(this.totalRows, this.pageSize);var showPageNum = 1,showListIndex = 0;if (this.totalPage > this.pageNumAmount) {showPageNum = this.pageNum - (this.pageNumAmount >> 1); //顯示的第一個(gè)頁(yè)號(hào)if (this.totalPage - showPageNum < this.pageNumAmount) {//末尾幾頁(yè)頁(yè)號(hào)數(shù)不夠的時(shí)候showPageNum = this.totalPage - this.pageNumAmount + 1;}showPageNum = showPageNum < 1 ? 1 : showPageNum;}this.showPageList = []; //先清空原來(lái)的數(shù)據(jù)for (var currentNum = 0; currentNum < this.pageNumAmount; ++currentNum, showPageNum++) {if (showPageNum > this.totalPage) {break;}this.showPageList[showListIndex++] = showPageNum;}if (this.pageNum > this.totalPage && this.pageNum > 1){//刪除最后一頁(yè)的最后一條數(shù)據(jù)后,pageNum需要更改過(guò)來(lái)if (this.totalPage > 0) {this.pageNum = this.totalPage;this.invokeAjaxMethod();} else {//刪除了所有數(shù)據(jù)this.pageNum = 0;}}},getNumMultiple(rawNum, baseNum, greedy = true) {var muti = parseInt(rawNum / baseNum);if (greedy && rawNum % baseNum > 0) {muti++;}return muti;}},template:'<div class="row">' +'<div class="col-4">' +'<div class="dataTables_info">共{{totalRows}}條記錄</div>' +'</div>' +'<div class="col-4" style="white-space: nowrap;">' +'<nav aria-label="..." class="float-right">' +'<ul class="pagination pagination-sm">' +'<li class="page-item">' +'<button :class="pageNum <= 1 ? \'btn-disabled\': \'\'" class="page-link" @click="prePage()">上一頁(yè)</button>' +'</li>' +'<li v-for="pageItemNo in showPageList" class="page-item" :class="pageItemNo == pageNum ? \'active\': \'\'">' +'<a class="page-link" @click="goPage(pageItemNo)" href="javascript:void(0)">{{pageItemNo}}<span class="sr-only"></span></a>' +'</li>' +'<li class="page-item">' +'<button :class="pageNum >= totalPage ? \'btn-disabled\' : \'\'" class="page-link" @click="nextPage()">下一頁(yè)</button>' +'</li>' +'<span style="line-height: 27px;">共{{totalPage}}頁(yè)</span>' +'</ul>' +'</nav>' +'</div>' +'<div class="col-4">' +'<div style="display: inline-flex;">' +'<label style="line-height: 27px;">到第</label>' +'<input v-model="inputPage" class="form-control form-control-sm" type="text" style="width: 80px;" maxlength="10"/>' +'<label style="line-height: 27px;">頁(yè)</label>' +'<button style="height: 30px;line-height: 15px;" @click="toSpecialPage" class="btn btn-confirm">確定</button>' +'</div>' +'</div>' +'</div>' });//單元格組件Vue.component('table-column', {props: {label: {//td展示的內(nèi)容default: ""},view: {//是否展示type: Boolean,default: true},render: {type: Function},item: {type: Object,required: true}},data(){return {itemStyle: ''}},created() {if (!this.view && "undefined" != typeof this.view) {this.itemStyle += "display: none";}},render(h) {const that = this;if (that.render){return that.render(h, that.item);}return h("td", {style: that.itemStyle,class: 'table-td',domProps: {innerHTML:that.label}});} });//操作按鈕組件Vue.component('table-button', {props: {item: {//該條內(nèi)容type: Object,required: true}},data(){return {cls: this.item.cls,label: this.item.label}},created(){if (!this.cls) {this.cls = "btn btn-outline-info btn-sm"}},methods: {clickEvt(){this.$emit("handel-click", this.item);}},template: `<button v-text="label" :class="cls" @click="clickEvt"></button>` });//表格組件Vue.component("tt-table", {props: {pageSize: {type: Number,default: 2},rows: {//總數(shù)量default: 0},pageNo: {//當(dāng)前頁(yè)type: Number,default: 1},paging: {default: true},datas: {type: Array,required: true},columns: {type: Array,required: true}},data(){return {needPaging: this.paging,showList: []//當(dāng)前頁(yè)展示的內(nèi)容}},created(){if (this.needPaging == "false"){this.needPaging = false;//轉(zhuǎn)換成boolean} else {if (this.needPaging && this.needPaging != "true"){this.needPaging = true;}}this.handlePaging(1);},render(h){const that = this;var cols = new Array();var heads = new Array();//組裝columnthat.columns.forEach((item, index) => {var colWidth = item.width;if (!colWidth) {colWidth = "15%";}let columnStyle = {width: colWidth};if (!item.view && typeof item.view != "undefined"){columnStyle.display = "none";}cols.push(h("col", {style: columnStyle}));if (item.sort){heads.push(h("th", {style: columnStyle}, [h("label", item.label),h("span", {on: {click: function(){that.handleOrder(item.code, true);}}}, "↑"),h("span", {on: {click: function(){that.handleOrder(item.code, false);}}}, "↓")]));} else {heads.push(h("th", {style: columnStyle}, item.label));}});var tbodys = new Array();that.showList.forEach((item, index) =>{var tds = new Array();that.columns.forEach((columnItem, columnIndex) =>{if (columnItem.code == 'opt') {//組裝操作按鈕let optBtns = [];columnItem.datas.forEach((btnItem) => {optBtns.push(h("table-button", {props: {item: btnItem},on: {'handel-click': function(obj){btnItem.clickHander(obj);}}}));});tds.push(h("td",{props:{label: ""}}, optBtns));} else {tds.push(h("table-column", {props: {label: item[ columnItem.code ],item: item,render: columnItem.render,view: columnItem.view//是否展示}}));}});tbodys.push(h("tr", tds));});if (that.needPaging) {return h("div", [h("div", {class: "table-responsive",style: "margin-top: 10px;"}, [h("table", {class: "table mb-0 table-striped"}, [h("colgroup", cols),h("thead", [h('tr', heads)]),h("tbody", tbodys)])]),h("page-split", {props: {totalRows: window.parseInt( that.rows ),pageNum: that.pageNo,pageSize: that.pageSize},domProps: {pageNum: that.pageNo,},on: {'switch-page': function(thisPage){that.pageNo = thisPage;that.handlePaging(thisPage);}}})]);} else {return h("div", {class: "table-responsive",style: "margin-top: 10px;"}, [h("table", {class: "table mb-0 table-striped"}, [h("colgroup", cols),h("thead", [h('tr', heads)]),h("tbody", tbodys)])]);}},methods: {/*** 處理排序*/handleOrder(sortedCode, isAsc){//如果是數(shù)字或者時(shí)間則按照大小排序,字符串則按照長(zhǎng)短進(jìn)行排序//找出一個(gè)非空的列var firstSortVal = '';for (let key in this.showList) {if (this.showList[key][sortedCode]) {firstSortVal = this.showList[key][sortedCode];break;}}if (!firstSortVal) {return false;}//判斷類型var columnType = 0;//0-2分別標(biāo)識(shí)string,number,date類型if (typeof window.parseFloat(firstSortVal) == "number") {columnType = 1;} else {let tempDate = new Date(firstSortVal);if (tempDate instanceof Date) {columnType = 2;}}var sortedFunction = '';switch (columnType){case 0:if (isAsc) {sortedFunction = function(a, b){return a[sortedCode].length < b[sortedCode].length ? -1 : 1;}} else {sortedFunction = function(a, b){return a[sortedCode].length > b[sortedCode].length ? -1 : 1;}}break;case 1:if (isAsc) {sortedFunction = function(a, b){return window.parseFloat(a[sortedCode]) < window.parseFloat(b[sortedCode]) ? -1 : 1;}} else {sortedFunction = function(a, b){return window.parseFloat(a[sortedCode]) > window.parseFloat(b[sortedCode]) ? -1 : 1;}}break;case 2:if (isAsc) {sortedFunction = function(a, b){return new Date( a[sortedCode] ) < new Date( b[sortedCode] ) ? -1 : 1;}} else {sortedFunction = function(a, b){return new Date( a[sortedCode] ) > new Date( b[sortedCode] ) ? -1 : 1;}}break;}this.showList.sort(sortedFunction);},/**處理分頁(yè)*/handlePaging(pageNo){var showList = this.datas.slice((pageNo -1) * this.pageSize, pageNo * this.pageSize);this.showList = [].concat(showList);}} });//掛載實(shí)例: new Vue({el: "#app",data: {label: "hello world from vue inst",rows: 0,columns: [{code: "id",label: "ID",sort: true},{code: "name",label: "姓名",render: function(h, item){const that = this;return h({template: "<td>" + that.label + "</td>"});}},{code: "age",label: "年齡"},{code: "opt",label: "操作",datas: [{label: "查看",cls: 'class',clickHander(item){window.alert("click view:" + JSON.stringify(item));}},{label: "編輯",cls: 'class',clickHander(item){window.alert("click edit:" + JSON.stringify(item));}}]}],datas: [{id: "1",name: "name1",age: 21},{id: "2",name: "name2",age: 22},{id: "3",name: "name3",age: 33},{id: "4",name: "name4",age: 44},{id: "5",name: "name5",age: 55},{id: "6",name: "name6",age: 66}]},created(){this.rows = this.datas.length;}});</script></body> </html>?
總結(jié)
以上是生活随笔為你收集整理的vue实现表格组件,带分页的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 单例模式volatile
- 下一篇: vue循环渲染子组件视图不更新问题