首先就是新建一个组件,名字就叫做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>