分享一款本身寫的table組件 用起來還算簡單好用 (先介紹使用方法(ts版本的))javascript
引入組件很少說css
import jTable from '../comp/comp/table/table.vue';//table
@Component({
components: {
jTable,
},
})
頁面使用vue
<j-table ref = "jtable" :tableOpt = "tableOpt"></j-table>
重點!!!!java
表格的配置git
tableOpt:object = { /** * @desc 表格數據來源請求(ajax地址) */ getUrl:function(){ return "/api/gettable" }, /** * @description 頁碼配置 * @example * index : number 開始頁碼 * pageSize : number 每頁多少條 * indexKey : string 後臺接口接受開始頁碼的key名 * pageSizeKey : string 後臺接口接受每頁多少條的key名 */ pageOption:{ index:5 , pageSize:1, indexKey:"index", pageSizeKey:"pageSize" }, /** * @description 數據處理函數 用於處理後臺返回的數據 須要返回一個json * data : array 包含一個json的數組,數據源 * index : number 當前頁碼 * total : number 總條數碼 * totalPage : number 總頁碼數 */ dataHandle(data:any){ return { data:data.rows, index:data.index, total:data.total, totalPage:data.totalPage, } }, /** * @description 表格中每一列的名字和須要取key值 */ titleMap:[ { name:"名字", key:"name", }, { name:"年齡", key:"age" }, { name:"手機號", key:"phone" }, { name:"年份", key:"year", }, { name:"月份", key:"month", }, { name:"月份", key:"month", }, { name:"日", key:"day", }, { name:"t", key:"t", }, { name:"z", key:"z", } ], /** * @description 表格按鈕 * val : string 按鈕文字 * callback : function 按鈕回掉函數(包含整行數據) * type : 按鈕的類型 詳情看button組件 * threed 按鈕是不是3d的 * text 按鈕是不是文字形的 */ actions:[ { val:"操做1", callback:this.ccc, type:"primary", threed : false, text:false, }, { val:"操做2", callback:this.ddd, type:"primary", threed : true, text:false, }, { val:"操做3", callback:this.ddd, type:"warning", threed : true, text:true, } ] }
就是這麼簡單 不過須要引入個人button組件 稍後補充下button組件的使用 感受秒殺element使用 github
接下來上table代碼web
<template> <div> <table class = "j-table-box" cellspacing="0" cellpadding="0"> <table-header :titleMap = "state.titleMap" :actions = "state.actions"></table-header> <table-body :data = "state.tableRows" :titleMap = "state.titleMap" :actions = "state.actions"></table-body> </table> <table-page :page = "state.tableInfo" :pkey = "$data.__key"></table-page> </div> </template> <script lang="ts"> /** * tableoptions interface */ interface tableOpt { getUrl:Function; pageOption:{ indexKey:string; index:number; pageSizeKey:string; pageSize:number; }; dataHandle:Function, titleMap:number[], actions:number[], } /** * tableArr interface */ interface tableArr { data:number[], total:number, index:number totalPage:number, } import { Vue, Component,Prop, Provide,} from 'vue-property-decorator'; import tableHeader from "./tableHeader.vue"; import tableBody from "./tableBody.vue"; import tablePage from "./tablePage.vue"; import Fetch from "../../tool/fetch"; import Key from "../../tool/compConfig" function settableData(data:tableArr,that: any):void{ that.state.tableRows = data.data; that.state.tableInfo.total = data.total; that.state.tableInfo.totalPage = data.totalPage; that.state.tableInfo.index = data.index; } @Component({ components:{ tableHeader, tableBody, tablePage }, }) export default class jTable extends Vue{ @Prop() tableOpt !:tableOpt; state = { tableInfo : { pageSize:this.tableOpt.pageOption.pageSize, index:this.tableOpt.pageOption.index, total:0, totalPage:0, }, actions:this.tableOpt.actions ? this.tableOpt.actions : [], tableRows : [], titleMap:this.tableOpt.titleMap, } __key :number = Key.getKey(); mounted(){ var _this = this; this.$_event.$on(this.$data.__key+"TABLEEVENT",function(tag:any,...other:any[]):void{ if(!tag){ return ; } if(tag == "prePage"){ _this.renderTable(other[0]); } if(tag == "nextPage"){ _this.renderTable(other[0]); } if(tag == "appointPage"){ _this.renderTable(other[0]); } }) this.renderTable(); } beforeDestroy(){ this.$_event.$off("TABLEEVENT") } /** * @params {number} index 獲取的頁碼 */ renderTable(index?:number):void{ if(!index){ index = this.state.tableInfo.index } if(this.tableOpt.getUrl()){ Fetch.getFetch(this.tableOpt.getUrl(),{ [this.tableOpt.pageOption.indexKey]:index, [this.tableOpt.pageOption.pageSizeKey]:this.state.tableInfo.pageSize }).then((data:any) => { let array = this.tableOpt.dataHandle(data); settableData(array,this); console.log(this,111); }) .catch(error => { console.log(error,2222); }) } } /** * @description 獲取當前頁數 */ getCurrentPage(){ return this.state.tableInfo.index } /** * 獲取當前頁數據 */ getCurrentPageData(){ return this.state.tableRows } } </script> <style lang="scss"> .j-table-box{ width:100%; } </style>
<template> <tbody class = "j-table-body"> <tr v-for = "(row,rowKey) in data" :key = "rowKey"> <td v-if = "actions.length > 0"> <j-button v-for = "(config,index) in actions" :key = "index" inline :type = "config.type?config.type:'default'" :threed = "config.threed ? config.threed:false" :text = "config.text ? config.text:false" @click = "config.callback ? config.callback(row) : ''"> {{config.val ? config.val : '操做'}} </j-Button> </td> <td v-for = "(title,titleKey) in titleMap" :key = "titleKey"> {{ row[title.key] }} </td> </tr> </tbody> </template> <script lang = "ts"> import { Vue, Component,Prop, Provide,} from 'vue-property-decorator'; import jButton from "../button/button.vue"; @Component({ components:{ jButton } }) export default class jTableBody extends Vue{ @Prop({default:[]}) data ?:number[]; @Prop({default:[]}) titleMap ?:number[]; @Prop({default:[]}) actions ?:number[]; } </script> <style scoped> .j-table-body tr td { border:1px solid #aeaeae; text-align: center; } </style>
<template> <thead class = "j-table-header"> <tr> <th v-if = "actions.length > 0">操做</th> <th v-for = "(title,titleKey) in titleMap" :key = "titleKey"> {{ title.name }} </th> </tr> </thead> </template> <script lang = "ts"> import { Vue, Component,Prop, Provide,} from 'vue-property-decorator'; @Component({ }) export default class jTableHeader extends Vue{ @Prop({default:[]}) titleMap ?: number[]; @Prop({default:[],type:Array}) actions ?:number[]; } </script> <style scoped> .j-table-header tr th { border:1px solid #aeaeae; text-align: center; } </style>
<template> <div class = "j-table-page"> <ul class = "page-box"> <template v-if = "page.totalPage<=8"> <li class="page-btn" v-for = "(index,key) in page.totalPage" :class = "parseInt(page.index) == parseInt(index)?'current':'normal'" :key = "key" @click = "getPage(index)"> {{ index }} </li> </template> <template v-if = "page.totalPage > 8"> <li class="page-btn" v-for = "(index,key) in 2" :class = "parseInt(page.index) == parseInt(index)?'current':'normal'" :key = "'table_footer_start' + key" @click = "getPage(index)"> {{ parseInt(index) }} </li> <li class = "page-btn-ellipsis" v-show = 'page.index > 3' v-hover = "'<'" @click = "prePages(page.index-3)"> ... </li> <li class="page-btn normal" v-if = "parseInt(page.index)-1>3 && parseInt(page.index)-1<= page.totalPage-2" @click = "getPage(page.index-1)"> {{ page.index-1 }} </li> <li class="page-btn current" v-if = "parseInt(page.index)>2 && parseInt(page.index)<= page.totalPage-2" @click = "getPage(page.index)"> {{ page.index }} </li> <li class="page-btn normal" v-if = "parseInt(page.index)+1 <= page.totalPage-2 && parseInt(page.index)+1 > 2" @click = "getPage(page.index+1)"> {{ page.index+1 }} </li> <li class = "page-btn-ellipsis" v-show = 'parseInt(page.totalPage -3) > parseInt(page.index)' v-hover = "'>'" @click = "nextPages(page.index+3)"> ... </li> <li class="page-btn" v-for = "(index,key) in [1,0]" :class = "parseInt(page.totalPage) - parseInt(index) == page.index?'current':'normal'" :key = "'table_footer_last' + key" @click = "getPage(page.totalPage - index)"> {{ parseInt(page.totalPage) - parseInt(index) }} </li> </template> </ul> </div> </template> <script lang = "ts"> import { Vue, Component,Prop} from 'vue-property-decorator'; @Component({ }) export default class jTablePage extends Vue{ @Prop({default:[]}) page?:number[]; @Prop({}) pkey?:number[]; myThis:any = this; nextPages(page:number):void{ this.$_event.$emit(this.pkey + "TABLEEVENT","nextPage",page); } prePages(page:number):void{ this.$_event.$emit(this.pkey + "TABLEEVENT","prePage",page); } getPage(page:number):void{ this.$_event.$emit(this.pkey + "TABLEEVENT","appointPage",page); } } </script> <style scoped> .j-table-page{ width:100%; text-align: center; padding-top:10px; } .j-table-page .page-box{ width:50%; text-align:center; margin:0 auto; } .j-table-page .page-box .page-btn-ellipsis{ display:inline-block; list-style: none; margin-left: 10px; margin-right: 10px; vertical-align: top; cursor:pointer; } .j-table-page .page-box .page-btn{ width:30px; height:30px; background:#efefef; box-shadow: 0px 0px 3px #aeaeae; border-radius:5px; display:inline-block; list-style: none; line-height: 30px; margin-left:5px; } .j-table-page .page-box .page-btn:hover{ background:#e5e5e5; cursor:pointer; } .page-btn.current{ background:rgb(141, 141, 240)!important; color:#fff; } </style>
<template> <div :class = "{'j__box__inline':inline}"> <button class = "j__btn" :class = "[ type ? 'j__button__'+type : 'j__button__default', { 'j__button__text':text, 'j__button__circle':circle, 'j__button__3D':threed }, ]" v-on="$listeners"> <slot/> </button> </div> </template> <script lang="ts"> import { Vue,Component,Prop,Provide } from "vue-property-decorator"; @Component({}) export default class jButton extends Vue { @Prop() type ?:string; @Prop({default:false,type:Boolean}) inline ?: boolean; @Prop({default:false,type:Boolean}) text ?: boolean; @Prop({default:false,type:Boolean}) circle ?: boolean; @Prop({default:false,type:Boolean}) threed ?: boolean; } </script> <style scoped> .j__box__inline{ display:inline; margin-left:5px; margin-right:5px; } .j__btn { cursor: pointer; /* 鼠標移入按鈕範圍時出現手勢 */ outline: none; /* 不顯示輪廓線 */ font-size: 12px; /* 字體大小 */ border:1px solid #efefef; box-sizing:border-box; padding:5px 10px; border-radius: 3px; } .j__button__3D{ transition-duration: .3s; margin-top:10px; margin-bottom:10px; } .j__button__default { background:#fff; color:#333; } .j__button__default:hover { background:#efefef; color:#444; } .j__button__default.j__button__3D{ border:none!important; -webkit-box-shadow: 0 7px 0 #dbe5ec, 0 8px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 7px 0 #dbe5ec, 0 8px 3px rgba(0, 0, 0, 0.3); } .j__button__default.j__button__3D:active{ transform: translate(0,5px); -webkit-box-shadow: 0 0 0 #dbe5ec, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #dbe5ec, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__text.j__button__default:hover{ color:#999!important; } .j__button__text.j__button__3D.j__button__default{ border:none!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__text.j__button__3D.j__button__default:hover{ border:none!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__text.j__button__3D.j__button__default:active{ transform: translate(0)!important; border:none!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__primary { background:#069af4; color:#fff; } .j__button__primary:hover { background:#47b0f7; color:#fff; } .j__button__primary.j__button__3D{ border:none!important; -webkit-box-shadow: 0 7px 0 #0880d7, 0 8px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 7px 0 #0880d7, 0 8px 3px rgba(0, 0, 0, 0.3); } .j__button__text.j__button__primary:hover{ color:#069af4!important; } .j__button__text.j__button__3D.j__button__primary{ transform: translate(0)!important; border:none!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__primary.j__button__3D:hover{ background:#1194e6; } .j__button__primary.j__button__3D:active{ transform: translate(0,5px); -webkit-box-shadow: 0 0 0 #0880d7, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #0880d7, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__success { background:#a4de47; color:#fff; } .j__button__success:hover { background:#b8e56c; color:#fff; } .j__button__success.j__button__3D{ border:none!important; -webkit-box-shadow: 0 7px 0 #84b91f, 0 8px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 7px 0 #84b91f, 0 8px 3px rgba(0, 0, 0, 0.3); } .j__button__success.j__button__3D:hover{ background:rgb(146, 204, 53); } .j__button__success.j__button__3D:active{ transform: translate(0,5px); -webkit-box-shadow: 0 0 0 #84b91f, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #84b91f, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__text.j__button__success:hover{ color:#a4de47!important; } .j__button__text.j__button__3D.j__button__success{ transform: translate(0)!important; border:none!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__warning { background:#ffae2d; color:#fff; } .j__button__warning:hover { background:#ffc056; color:#fff; } .j__button__warning.j__button__3D{ border:none!important; -webkit-box-shadow: 0 7px 0 #e59501, 0 8px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 7px 0 #e59501, 0 8px 3px rgba(0, 0, 0, 0.3); } .j__button__warning.j__button__3D:active{ transform: translate(0,5px); -webkit-box-shadow: 0 0 0 #e59501, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #e59501, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__warning.j__button__3D:hover{ background:#f8a621; } .j__button__text.j__button__warning:hover{ color:#ffae2d!important; } .j__button__text.j__button__3D.j__button__warning{ transform: translate(0)!important; border:none!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__danger { background:#ff4356; color:#fff; } .j__button__danger:hover { background:#ff7680; color:#fff; } .j__button__danger.j__button__3D{ border:none!important; -webkit-box-shadow: 0 7px 0 #ff1022, 0 8px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 7px 0 #ff1022, 0 8px 3px rgba(0, 0, 0, 0.3); } .j__button__danger.j__button__3D:active{ transform: translate(0,5px); -webkit-box-shadow: 0 0 0 #ff1022, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #ff1022, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__danger.j__button__3D:hover{ background:#ea3c4d; } .j__button__text.j__button__danger:hover{ color:#ff4356!important; } .j__button__text.j__button__3D.j__button__danger{ border:none!important; transform: translate(0)!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__info { background:#909399; color:#fff; } .j__button__info:hover { background:#a6a9ad; color:#fff; } .j__button__info.j__button__3D { border:none!important; -webkit-box-shadow: 0 7px 0 #7b7d85, 0 8px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 7px 0 #7b7d85, 0 8px 3px rgba(0, 0, 0, 0.3); } .j__button__info.j__button__3D:hover{ background:#85888b; } .j__button__info.j__button__3D:active{ transform: translate(0,5px); -webkit-box-shadow: 0 0 0 #8a8c92, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #8a8c92, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__text.j__button__info:hover{ color:#909399!important; } .j__button__text.j__button__3D.j__button__info{ border:none!important; transform: translate(0)!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__remind { background:#7672e6; color:#fff; } .j__button__remind:hover { background:#a49eee; color:#fff; } .j__button__remind.j__button__3D{ border:none!important; -webkit-box-shadow: 0 7px 0 #5246e2, 0 8px 3px rgba(0, 0, 0, 0.3); box-shadow: 0 7px 0 #5246e2, 0 8px 3px rgba(0, 0, 0, 0.3); } .j__button__remind.j__button__3D:hover{ background:#6560ec; } .j__button__remind.j__button__3D:active{ transform: translate(0,5px); -webkit-box-shadow: 0 0 0 #5246e2, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #5246e2, 0 0 0 rgba(0, 0, 0, 0.3); } .j__button__text.j__button__remind:hover{ color:#7672e6!important; } .j__button__text.j__button__3D.j__button__remind{ border:none!important; transform: translate(0)!important; -webkit-box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 0 #7b7d85, 0 0 0 rgba(0, 0, 0, 0.3); } /* border類 */ .j__button__text{ border: 0px solid transparent!important; background:transparent!important; color:#333!important; margin:0!important; padding:0!important; } /* border radius 類 */ .j__button__circle{ border-radius:17px; } </style>
須要公用 js 文件 ajax
頁面全局須要 json
import event from "./comp/tool/event";
Vue.use(event);
這是註冊全局this.$event指令用於跨組件通訊api
/** * @description eventbus事件 * @author jinzz * created by 2018/05/25 * !!!取消事件訂閱必須跟事件訂閱成對出現,不然會重複訂閱,對javascript性能形成沒必要要的浪費。所以B組件銷燬前需取消當前事件訂閱。 * @param {any} event 第一個參數是事件對象,第二個參數是接收到消息信息,能夠是任意類型,更多參數也能夠留做擴展,使用...運算符方便更多操做 * @method $on 事件訂閱, 監聽當前實例上的自定義事件。https://cn.vuejs.org/v2/api/#vm-on * @method $off 取消事件訂閱,移除自定義事件監聽器。 https://cn.vuejs.org/v2/api/#vm-off https://github.com/vuejs/vue/issues/3399 * @method $emit 事件廣播, 觸發當前實例上的事件。 https://cn.vuejs.org/v2/api/#vm-emit * @method $once 事件訂閱, 監聽一個自定義事件,可是隻觸發一次,在第一次觸發以後移除監聽器。 https://cn.vuejs.org/v2/api/#vm-once */ export default { install:function(Vue:any){ const eventHub = new Vue() Vue.prototype.$_event = { $on (...event:any[]) { eventHub.$on(...event) }, $off (...event:any[]) { eventHub.$off(...event) }, $once (...event:any[]) { eventHub.$emit(...event) }, $emit (...event:any[]) { eventHub.$emit(...event) } } } }
須要fetch.ts(用於ajax請求(我只寫了get請求的,由於本身寫着玩的,本身寫的接口 因此只寫了get))
import Q from "q"; interface jsonType { [key: string]: string } let defer = Q.defer(); let _active = { jsonToString(d:jsonType){ var result = "" for (let name in <object>d) { if (typeof d[name] != 'function') { result += "&" + name + "=" + encodeURIComponent(d[name]); } } return result.substring(1) } } // var _publishurl:string = "http://10.112.7.77:3000" // var _publishurl:string = "http://192.168.1.108:3000" var _publishurl:string = "http://172.20.10.2:3000" const getFetch = (url:string,params?:any)=> { return new Promise ((resolve,reject) => { let headers = { 'Content-Type': 'application/json; charset=UTF-8' }; let _opt = { method:"get", headers:headers } fetch(_publishurl + url + "?" + _active.jsonToString(params),_opt) .then((response) => { return response.json(); }) .then((data) => { resolve(data); }) .catch((error) => { reject(error); }) }) } export default { getFetch, }
最後還須要一個compConfig用於生成獨立的key,保證頁面多個組件不會找錯
let __key:number = -1; export default { getKey(){ __key++; return __key; } }
到這基本就能夠了
下面簡單介紹button組件吧
使用方法:
inline :行內
circle : 圓角
<j-button inline circle threed @click = "ccc" text>
補充 : table組件暴露出來的函數功能
獲取當前頁碼