自带分页与loading的表格封装

原创 精选
开发 前端
我们的后台系统,大部分的表格都带有分页和loading,为了不做重复的工作,基于element-ui封装了一个自带分页与loading的组件,下面大致介绍一下我的设计思路。

首先就是新建一个组件,名字就叫做​​PageTable​​,​​template​​里面很简单,放上表格和分页。既然表格默认带有分页,分页的数据就放在组件内部

<template>
<div>
<el-table></el-table>

<el-pagination
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="page.current"
:page-size.sync="page.size"
:total="page.total"
/>
</div>
</template>

<script>
export default {
name: 'PageTable',
data() {
return {
page: {
current: 1,
size: 10,
total: 0
},
}
},
}
</script>

之后开始思考一个问题,就是表格的数据是从父组件传进来,还是放在组件自身。如果放在父组件里面,那么分页的变化每次都要​​emit​​事件通知父组件,这样我们把分页和表格合在一起就失去了意义,所以表格的数据是要放在组件自身的。

表格数据放在自身,父组件就需要传进来一个获取数据的方法,就叫做​​fetchData​​吧,在组件内部调用这个方法,就可以获取数据了。这个方法是需要知道当前分页的,并且返回数据和总条数,由此就可以定义​​fetchData​​了

interface ResponseStructure {
data: any[];
total: any;
}
interface fetchData {
(current: number, size: number): Promise<ResponseStructure>
}

现在我们的组件已经变成了这个样子

<template>
<div>
<el-table :data="tableData"></el-table>

<el-pagination
layout="total, sizes, prev, pager, next, jumper"
:current-page.sync="page.current"
:page-size.sync="page.size"
:total="page.total"
@size-change="search"
@current-change="getTableData"
/>
</div>
</template>

<script>
export default {
name: 'PageTable',
props: {
fetchData: {
type: Function,
required: true
},
},
data() {
return {
page: {
current: 1,
size: 10,
total: 0
},
tableData: []
}
},
methods: {
search() {
this.page.current = 1
this.getTableData()
},
async getTableData() {
try {
const { current, size } = this.page
const { data, total } = await this.fetchData(current, size)
this.tableData = data
this.page.total = total
} catch (err) {
this.tableData = []
this.page.total = 0
}
},
}
}
</script>

表格一般都会带有搜索项,搜索参数等在父组件定义,并且逻辑写在​​fetchData​​里即可,组件内部只处理通用的逻辑。父组件里点击了搜索按钮,是要触发获取事件的,父组件可以通过​​$refs​​调用组件内部方法。目前我们定义了两个方法​​search​​与​​getTableData​​,点击搜索调用​​search​​就可以了,并且会自动重置分页,如果有不想重置分页的情况,可以调用​​getTableData​​。

目前为止,数据我们已经有了,但是并没有展示,因为element-ui的列信息(Table-column)是通过插槽的,我们使用​​slot​​接收一下就可以了

<el-table :data="tableData">
<slot />
</el-table>

到了这里基本逻辑已经完成了,再进一步,一般我们的表格需要loading,loading应该由父组件自己决定如何使用,但是状态的改变由本组件处理,这里可以使用​​.sync​​修饰符,loading逻辑加在 ​​getTableData​​中即可

<script>
export default {
props: {
loading: {
type: Boolean,
default: false,
},
},
methods: {
async getTableData() {
try {
const { current, size } = this.page
this.$emit('update:loading', true)
const { data, total } = await this.fetchData(current, size)
this.tableData = data
this.page.total = total
} catch (err) {
this.tableData = []
this.page.total = 0
} finally {
this.$emit('update:loading', false)
}
},
}
}
</script>

loading也加完了,功能就已经完成了,但是还存在一些问题,el-table有很多的Attributes、Events和Methods,Attributes和Events我们透传给el-table即可,Methods需要el-table的ref,如果父组件直接使用ref,获取的是组件外层的div,无法获取到el-table的ref,我们暴露一个方法抛出el-table的ref即可

<template>
<div>
<el-table v-bind="$attrs" v-on="$listeners" ref="tableRef" :data="tableData">
<slot />
</el-table>
</div>
</template>

<script>
export default {
methods: {
getTableRef() {
return this.$refs.tableRef
}
}
}
</script>

至此,​​PageTable​​就写完了,完整代码如下

<template>
<div>
<el-table
v-bind="$attrs"
v-on="$listeners"
ref="tableRef"
:data="tableData"
@sort-change="sortChange"
>
<slot />
</el-table>

<el-pagination
layout="total, sizes,prev, pager, next, jumper"
:current-page.sync="page.current"
:page-sizes="pageSizes"
:page-size.sync="page.size"
:total="page.total"
@size-change="search"
@current-change="getTableData"
/>
</div>
</template>

<script>
export default {
name: 'PageTable',
props: {
/**
* 获取表格数据的请求方法
* @param {Number} current 当前页数
* @param {Number} size 每页条数
* @param {Object} sort 排序
* @param {String} sort.orderBy 排序的key
* @param {('ascending'|'descending'|null)} sort.rule 排序的规则
*/
fetchData: {
type: Function,
required: true
},
pageSizes: {
type: Array,
default: () => [ 10, 20, 50, 100, 150 ]
},
loading: {
type: Boolean,
default: false
},
},
data() {
return {
page: {
current: 1,
size: 10,
total: 0
},
tableData: [],
sort: {
orderBy: '',
rule: ''
}
}
},
created() {
this.getTableData()
},
methods: {
/** 搜索,可通过 $refs 调用此方法 */
search() {
this.page.current = 1
this.getTableData()
},
/** 获取表格数据,可通过 $refs 调用此方法 */
async getTableData() {
try {
const { current, size } = this.page
this.$emit('beforeFetch')
this.$emit('update:loading', true)
const { data, total } = await this.fetchData(current, size, this.sort)

this.$emit('fetched', data)
this.tableData = data
this.page.total = total
} catch (err) {
this.$emit('fetched', [])
this.tableData = []
this.page.total = 0
} finally {
this.$emit('update:loading', false)
}
},
/** 获取el-table的ref,可通过 $refs 调用此方法 */
getTableRef() {
return this.$refs.tableRef
},
sortChange({ prop, order }) {
this.sort = {
orderBy: prop,
rule: order || ''
}
this.getTableData()
}
}
}
</script>
责任编辑:庞桂玉 来源: 之家技术
相关推荐

2011-05-18 14:49:53

MySQL分页

2023-10-12 07:29:24

MySQL分页数据量

2021-11-22 10:00:33

鸿蒙HarmonyOS应用

2012-05-29 15:22:03

JACOBJava

2010-09-14 14:23:08

DIV+CSS

2010-09-13 13:44:35

CSS表格CSS表单

2010-06-01 16:34:06

IPv6协议

2021-03-04 08:19:29

插件机制代码

2011-01-26 08:59:11

jQueryjavascriptweb

2013-10-12 13:26:08

设计加载

2009-06-02 10:42:31

PLSQL动态SQL

2010-06-04 14:18:10

MySQL 分页存储过

2010-04-30 10:01:09

Oracle 分页

2022-02-16 08:58:05

开发项目MybatisPlu分页工具

2011-08-10 17:38:56

Windows7自带的WinZip

2023-10-19 13:24:00

Java工具

2010-08-16 15:32:06

DIV+CSS

2023-05-08 06:52:47

开源PythonAPI

2009-07-20 16:18:54

iBatis分页Hibernate式的

2009-06-08 16:44:00

点赞
收藏

51CTO技术栈公众号