項目中使用了Element UI的表格組件el-table,按照官方提供的寫法,展示的列越多,代碼量也就越大。如果是開發后臺管理系統,需要用到統計的地方有很多。不把時間花在重復的工作上,封裝el-table,作為組件引用,只需要少量的配置,就能極大的提高開發效率。
el-table需要面對的場景多種多樣,業務不同,呈現出的樣式也不同,根據使用的難易程度,把它分為:
- 1、顯示數據從父視圖傳遞,集成只需要一行代碼的簡易表格——
<simpleTable>
- 2、集成需要配置請求接口、查詢參數,有分頁,組件內請求數據的表格——
<myTable>
一、simpleTable
<template>
<div ref="table" >
<el-table :show-summary="isShowSummary" v-if="!fixHeight" :header-cell-style="{background:headerBgColor}" :data="tableData" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange">
<el-table-column v-if="isShowSelection" type="selection" width="55" align="center"></el-table-column>
<el-table-column type="index" align="center" label="序號" min-width="50" v-if="isShowSerialNumber"></el-table-column>
<template v-for="k in props">
<el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
<el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
</template>
<el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
<slot name="operation" :data="scope.row" slot-scope="scope"></slot>
</el-table-column>
</el-table>
<el-table v-else :height="tableH" :show-summary="isShowSummary" :header-cell-style="{background:headerBgColor}" :data="tableData" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange">
<el-table-column v-if="isShowSelection" type="selection" width="55" align="center"></el-table-column>
<el-table-column type="index" align="center" label="序號" min-width="50" v-if="isShowSerialNumber"></el-table-column>
<template v-for="k in props">
<el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
<el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
</template>
<el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
<slot name="operation" :data="scope.row" slot-scope="scope"></slot>
</el-table-column>
</el-table>
</div>
</template>
<script>
export default {
props: {
headerBgColor: {
type: String,
default: 'white'
},
fixHeight:{
type: Boolean,
default: false
},
tableH:{
type: Number,
default: 0
},
isShowSelection: {
type: Boolean,
default: false
},
isShowSerialNumber: {
type: Boolean,
default: true
},
isShowOperation: {
type: Boolean,
default: true
},
isShowSummary: {
type: Boolean,
default: false
},
fixedType:{
type: Boolean,
default: false
},
sort: {
type: Array,
default: () => []
},
props: Array,
tableData: {
type: Array,
default: () => []
},
},
data () {
return {
}
},
created () {},
mounted(){},
methods: {
handleSelectionChange (val) {
this.$emit('selectionChange', val)
}
}
}
</script>
SimpleTable
參數 | 說明 | 類型 | 默認值 |
---|---|---|---|
headerBgColor | 表頭背景色 | String | white |
fixHeight | 是否固定表格高度 | boolean | false |
tableH | 表格高度(fixHeight為true, 則tableH必須設定) | number | 0 |
isShowSelection | 是否開啟選擇功能 | boolean | false |
isShowSerialNumber | 是否顯示序號 | boolean | true |
isShowOperation | 是否顯示操作列 | boolean | true |
isShowSummary | 是否顯示總計 | boolean | true |
fixedType | 是否固定右側操作欄 | boolean | false |
props | 列標題以及對應的參數名數組 | Array | [] |
tableData | 后臺返回的數據 | Array | [] |
Table Events
事件名 | 說明 | 參數 |
---|---|---|
selectionChange | 當選擇項發生變化時會觸發該事件 | row |
使用方式:
<template>
<div class="h-table">
<simpleTable
:tableData="chartData2.rows"
:props="callProps">
<template #operation="{ data }">
<a href="javascript:;">查看詳情</a>
</template>
</simpleTable>
</div>
</template>
<script>
import simpleTable from "./../components/simpleTable";
export default {
name: "home",
components: {
simpleTable
},
data() {
return {
callProps: [
{
prop: "date",
label: "日期",
fixw: "150" // 自定義某列寬度
},
{
prop: "callNum",
label: "外呼數",
sort: true // 是否可以篩選
},
{
prop: "callSuccess",
label: "外呼成功數",
},
{
prop: "connectNum",
label: "接通率",
},
{
prop: "connectDuring",
label: "外呼平均通話時長",
},
],
chartData2: {
rows: [
{ date: "2020-03-04", callNum: 1393, callSuccess: 1093 },
{ date: "2020-03-05", callNum: 3530, callSuccess: 3230 },
{ date: "2020-03-06", callNum: 2923, callSuccess: 2623 },
{ date: "2020-03-07", callNum: 1723, callSuccess: 1423 },
{ date: "2020-03-08", callNum: 3792, callSuccess: 3492 },
{ date: "2020-03-09", callNum: 4593, callSuccess: 4293 },
],
},
};
}
};
</script>
<style lang="scss" scoped>
.h-table{
width: 90%;
margin-top: 20px;
margin-left: 20px;
}
</style>
二、myTable
<template>
<div ref="table" v-loading="loading" >
<el-table v-if="!fixHeigth" :data="tableData" :header-cell-style="{background:headerBgColor}" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange" @sort-change="handleSortChange">
<el-table-column v-if="isShowSelection" type="selection" width="55" align="center" :selectable="isSelectable"></el-table-column>
<el-table-column align="center" label="序號" min-width="70" v-if="isShowSerialNumber">
<template slot-scope="scope">
<span>{{scope.$index+(currentPage-1)*pageSize+1}}</span>
</template>
</el-table-column>
<template v-for="k in props">
<el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
<el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
</template>
<el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
<slot name="operation" :data="scope.row" slot-scope="scope"></slot>
</el-table-column>
</el-table>
<el-table v-else :height="tableH" :data="tableData" :header-cell-style="{background:headerBgColor}" ref="multipleTable" border style="width: 100%;" @selection-change="handleSelectionChange" @sort-change="handleSortChange">
<el-table-column v-if="isShowSelection" type="selection" width="55" align="center" :selectable="isSelectable"></el-table-column>
<el-table-column align="center" label="序號" min-width="70" v-if="isShowSerialNumber">
<template slot-scope="scope">
<span>{{scope.$index+(currentPage-1)*pageSize+1}}</span>
</template>
</el-table-column>
<template v-for="k in props">
<el-table-column v-if="k.fixw" :min-width="k.fixw" align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
<el-table-column v-else align="center" :prop="k.prop" :label="k.label" :sortable="k.sort ? true : false">
<slot :name="k.prop" :data="scope.row" slot-scope="scope">{{scope.row[k.prop]}}</slot>
</el-table-column>
</template>
<el-table-column align="center" :fixed="fixedType?'right':fixedType" label="操作" v-if="isShowOperation">
<slot name="operation" :data="scope.row" slot-scope="scope"></slot>
</el-table-column>
</el-table>
<div class="bottom-row" v-if="isShowPagination">
<el-pagination
@current-change="handleCurrentChange"
:page-size="pageSize"
:current-page.sync="currentPage"
layout="prev, pager, next, jumper, total"
:total="total">
</el-pagination>
</div>
</div>
</template>
<script>
export default {
props: {
headerBgColor: {
type: String,
default: 'white'
},
isShowSelection: {
type: Boolean,
default: false
},
immediate: {
type: Boolean,
default: true
},
fixHeigth:{ //固定高度
type: Boolean,
default: false
},
isShowSerialNumber: {
type: Boolean,
default: true
},
isShowOperation: {
type: Boolean,
default: true
},
isShowPagination: {
type: Boolean,
default: true
},
isSecondLayer: {
type: Boolean,
default: true
},
isPost: {
type: Boolean,
default: true
},
isCustomTime:{ // 起始時間劃分為兩個參數的情況
type: Boolean,
default: false
},
tableH:{ // 表格高度,橫向內容超過可視區域時適配小屏幕電腦
type: Number,
default: 0
},
fixedType:{ // 是否固定右側操作欄
type: Boolean,
default: false
},
isArray: {
type: Boolean,
default: true
},
callback: Function,
sort: {
type: Array,
default: () => []
},
query: Object,
props: Array,
action: String,
isSelectable: Function,
dataList: String,
selected: String
},
data () {
return {
loading: false,
tableData: [],
total: 0,
pageSize: 10,
currentPage: 1
}
},
async created () {
this.immediate && await this.search()
},
methods: {
async search (i, isScroll) {
this.currentPage = i > 0 ? i : this.currentPage
let query = JSON.parse(JSON.stringify(this.query))
for (let key in query) {
if (Array.isArray(query[key])) {
query[key] = query[key].toString()
}
}
let req = {
pageNum: this.currentPage,
pageSize: this.pageSize,
...query
}
if(this.isCustomTime){
let paytime=this.query.payTime || [];
req.payTimeStart=paytime[0]
req.payTimeEnd=paytime[1]
}
this.loading = true
if (this.isPost) {
this.$api.post(this.action, req, r => {
this.loading = false
this.handleOperation(r, isScroll)
})
} else {
this.$api.get4(this.action, req, r => {
this.loading = false
this.handleOperation(r, isScroll)
})
}
},
handleOperation (r, isScroll) {
if (r.flag) {
this.callback && this.callback(r) // 如果要對返回值做額外操作
if (this.isSecondLayer) { // 有分頁
if(r.data.allNum){
this.total = +r.data.allNum
}else{
this.total = +r.data.total
}
if (!this.dataList) { // 如果接口返回的data數據為dataList,根據實際情況而定
this.tableData = r.data.dataList
} else { // 其他參數名時取值
this.tableData = r.data[this.dataList]
}
} else { // 沒有分頁
if (this.isArray) { // 如果數據類型為數組
this.tableData = r.data
} else { // 如果數據類型為非數組
this.tableData = []
this.tableData.push(r.data)
}
}
this.selected && this.handleTest()
isScroll && this.$refs.table.scrollIntoView({behavior: 'smooth', block: 'start'})
}
},
handleCurrentChange (index) {
this.search(index, true)
},
handleSortChange (val) {
this.$emit('sortChange', val)
},
handleSelectionChange (val) {
this.$emit('selectionChange', val)
},
handleSizeChange (val) {
this.pageSize = val
this.search(1, true)
},
handleTest () {
const rows = this.selected.split(',')
this.tableData.forEach((row, i) => {
rows.forEach(_ => {
if (row.id === parseInt(_)) {
this.$nextTick(() => {
this.$refs.test.toggleRowSelection(row, true)
})
}
})
})
},
clearSelected () {
this.$refs.multipleTable.clearSelection()
}
}
}
</script>
<style lang="scss" scoped>
</style>
myTable
參數 | 說明 | 類型 | 默認值 |
---|---|---|---|
headerBgColor | 表頭背景色 | String | white |
fixHeight | 是否固定表格高度 | boolean | false |
tableH | 表格高度(fixHeight為true, 則tableH必須設定) | number | 0 |
isShowSelection | 是否開啟選擇功能 | boolean | false |
isShowSerialNumber | 是否顯示序號 | boolean | true |
isShowOperation | 是否顯示操作列 | boolean | true |
isShowSummary | 是否顯示總計 | boolean | true |
fixedType | 是否固定右側操作欄 | boolean | false |
props | 列標題以及對應的參數名數組 | Array | [] |
tableData | 后臺返回的數據 | Array | [] |
immediate | 是否創建即請求數據 | boolean | true |
isShowPagination | 是否顯示底部的分頁器 | boolean | true |
isSecondLayer | 是否有分頁 | boolean | true |
isPost | 是否為post請求 | boolean | true |
isCustomTime | 起始時間劃分為兩個參數的情況 | boolean | false |
isArray | 返回數據是否為數組形式 | boolean | true |
query | 查詢參數 | Object | { } |
action | 請求接口 | String | 必傳 |
dataList | 獲取data數據的key值 | String | r.data[dataList] |
使用方式:
- 1、數據結構為非數組,只顯示一行的統計類表格
data:{
redAmount: "632.00"
people: 3
gift: 11
}
<template>
<div>
<el-date-picker
style="width:220px;"
size="small"
clearable
value-format="yyyy-MM-dd"
v-model="searchInfo.time"
type="daterange"
:picker-options="$utils.pickerOptions"
range-separator="至"
start-placeholder="時間選擇"
end-placeholder="時間選擇">
</el-date-picker>
<el-button type="primary" size="small" @click="$refs.table.search(1)">查詢</el-button>
<mytable style="padding: 10px;" :isArray="false" :action="action" :query="searchInfo" :props="props" ref="table" :isShowSerialNumber="false" :isShowPagination="false" :isSecondLayer="false" :isShowOperation="false"></mytable>
</div>
</template>
<script>
export default {
data() {
return {
action: this.$api.baseUrl + 'xxx/xxx/xxxx',
searchInfo: {
time: ''
},
props: [
{
prop: 'uvNum',
label: '落地頁uv'
},
{
prop: 'people',
label: '紅包領取人數'
},
{
prop: 'gift',
label: '堅果禮包領取人數'
}
],
};
},
};
</script>
- 2、常用統計表
<mytable dataList="records" :fixedType="true" style="padding: 10px;" :action="action1" :query="searchInfo" :props="props1" ref="table1">
<template #status="{data}">
<p class="status-reject" v-if="data.status === 0">審核不通過</p>
<p class="status-pass" v-if="data.status === 1">審核通過</p>
<p class="status-wait" v-else>未審核</p>
</template>
<template #operation="{data}">
<p class="detail" v-if="!data.status" @click="statusAction(data,1)">審核通過</p>
<p></p>
</template>
</mytable>
<script>
export default {
data() {
return {
action1: this.$api.baseUrl + 'xxx/xxx/xxxx',
searchInfo: {
time: ''
},
props1: [
{
prop: 'uvNum',
label: '落地頁uv'
},
{
prop: 'people',
label: '紅包領取人數'
},
{
prop: 'gift',
label: '堅果禮包領取人數'
},
{
prop: 'status' ,
label: '審核狀態'
}
],
};
},
};
</script>