基于 elementui 的时间组件,分页组件的二次封装
在后台管理系统中,开发人员面临最多的开发任务,table 数据管理应有一席之地。而随之而来的,就是数不清的筛选,排序操作。
而且每个table,都会配置一个分页用来更好的显示数据。
本文就从这个需求触发,来聊一聊时间组件和分页组件的二次封装。
为什么要二次封装
elementui 的各种组件做的很友好,但偶尔神经的产品就是不喜欢大众风格,非得独树一帜
这时候,在每个有 table 的位置都去做一个繁琐的分页,可以想像一下发生的问题:
- 代码量增加不少,阅读就会很繁琐;
- 工作量也增加不少;
- 更重要的是,不利于维护,比方 ui 姐姐改了一个显示效果,就会让人很头痛。
如何友好的二次封装一个组件
以分页效果为例。
假如我希望在每个需要分页组件的地方,只需要敲一行代码就可以,比如<pagi-nation @pageEvent="handleCurrentChange" :count="count"/>
那么,就需要基于 elementui 现有的分页进行再次封装。
首先,确定一下思路:
- 子组件需要总页数、当前页数、每页数据量、总页数等信息
- 总页数是父组件传递过来(prop),其他则可以直接在子组件中定义或者计算出来
- 父组件需要当前页数、总页数信息
- 总页数需要传递给子组件,当前页是子组件传递过来(emit)
- 考虑到每个需要分页的父组件,都需要总页数信息、当前页和表格数据,我们可以定义一个mixin,来专门提供这几个属性。
实现
1、实现分页子组件
<template>
<el-pagination
background
layout="slot, prev, pager, next"
@current-change="handleCurrentChange"
:current-page.sync="page"
:page-size="pageSize"
:prev-text="$tt('pagination.上一页')"
:next-text="$tt('pagination.下一页')"
:total="count"
>
<span
v-html="$tt('pagination.page', { totalCount: count, pageCount: pages })"
></span>
</el-pagination>
</template>
<script lang='ts'>
// $tt 是全局挂载的国际化,可以参考 i18n
import { Component, Vue, Prop, Emit } from 'vue-property-decorator'
@Component({})
export default class extends Vue {
@Prop({ default: 0 }) private count!: number;
// data属性
private pageSize = 15 // 每页15条数据
private page: number = 0 // 当前页码,默认0,即获取数据时的偏移量是0
// 向父组件通信,告诉父组件当前页码,用于计算获取数据的偏移量
@Emit('pageEvent')
private handleCurrentChange (val: number) {
this.page = val || this.page
return this.page
}
// computed 计算总页数
get pages () {
return Math.ceil(this.count / this.pageSize)
}
}
</script>
2、 实现提供共有属性的mixin
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class TableMixin extends Vue {
page = 0
count = 0
tableData = []
}
3、在父组件中引入和使用
<template>
<div>
<el-table :data="tableData>
</el-table>
<pagi-nation @pageEvent="handleCurrentChange" :count="count"/>
</div>
</template>
<script lang="ts">
import pagiNation from '@/views/components/pagination.vue'
import tableMiXin from '@/mixins/table'
import { Component, Vue, Watch, Prop, Emit } from 'vue-property-decorator'
@Component({
components: { pagiNation },
mixins: [ tableMiXin ] //提供tableData、page、count属性
})
export default class extends Vue {
private handleCurrentChange (page: number) {
this.page = page || this.page
this.getData() // 获取数据
}
async getData(){
let {list: tableData, count} = await getList({offset: 15 * this.page})
this.tableData = tableData
this.count = count
}
}
</script>
这样,一个基于 elementui 的分页组件的二次封装就完成了。
总结
这里需要注意的是,利用 mixin 来对多个组件的共有属性进行定义和注入,这样做
- 可以极大的减少在组件内部定义属性和方法的数量,提高编程效率
- 便于代码的维护与更改,
- 优化了代码结构,提高可读性
思考
假如现在要对日期组件进行封装,我们知道,表格的日期筛选一般都是有开始时间和结束时间两个选项,这就要求我们需要对起止时间有严格的判断,那么,这怎么来做呢?
首先,依旧要做一个日期子组件
<template>
<div>
<div>
<span>开始时间:</span>
<el-date-picker
v-model="startDate"
type="datetime"
@change="checkTime"
value-format="yyyy-MM-dd HH:mm:ss"
:placeholder="$tt('placeholder.开始时间')"
:picker-options="sOption"
>></el-date-picker
>
</div>
<div>
<span>结束时间:</span>
<el-date-picker
v-model="endDate"
type="datetime"
@change="checkTime"
value-format="yyyy-MM-dd HH:mm:ss"
:placeholder="$tt('placeholder.结束时间')"
:picker-options="eOption"
></el-date-picker>
</div>
</div>
</template>
<script>
export default {
data () {
return {
startDate: '',
endDate: '',
sOption: {
disabledDate: (time) =>
this.endDate
? time.getTime() > Date.now() ||
time.getTime() > new Date(this.endDate).getTime()
: time.getTime() > Date.now()
},
eOption: {
disabledDate: (time) =>
this.startDate
? time.getTime() > Date.now() ||
time.getTime() < new Date(this.startDate).getTime()
: time.getTime() > Date.now()
}
}
},
methods: {
checkTime () {
let { startDate, endDate } = this
let sDate = new Date(startDate)
let eDate = new Date(endDate)
if (e && sDate > eDate) {
this.$message.info('开始时间不能大于结束时间')
this.endDate = ''
} else {
this.$emit('getTime', { startDate, endDate })
}
}
}
}
</script>
其次,要把父组件的共有属性方法抽取到一个 mixin 中
import { Vue, Component } from 'vue-property-decorator'
@Component
export default class DateMixin extends Vue {
startDate = ''
endDate = ''
getTime (timeObj) {
this.startDate = timeObj.startDate
this.endDate = timeObj.endDate
}
}
写完以后,就可以在父组件中使用了。