Appearance
需求分析 #
一个管理系统的分页基本上样式以及布局都是一样的,不然也没必要封装一层,这边主要需要3个属性,以及1个事件。
- total 传递数据总数量,这个是单向数据流,是后台返回的数据量
- pageNum传递当前页码,这个是需要双向绑定的,因为这个是父组件初始化,后期根据用户操作 elementUI 返回新的页码,这个主要用于后台请求数据的一个参数。
- pageSize传递当前一页的大小,这个是需要双向绑定的,因为这个是父组件初始化,后期根据用户操作 elementUI 返回新的页码,这个主要用于后台请求数据的一个参数。
- 监听pageNum,pageSize的change事件,虽然也可以在父组件通过watch监听变量,不过那样代码就比较多了,可以直接监听change事件,触发就直接调用自定义的请求数据接口getList...
分页el-pagination的二次封装分析 #
1. 效果图 #
2. 查看elementUI组件的配置 #
从中可以看出:
- 单向数据流total,是用来展示总共有多少条数据的,主要从父组件=>封装子组件=>elementUI组件,主要是由父组件控制。
- 双向数据绑定current-page,以及page-size,分别代表当前页码以及每一页的数据量。
- current-page,以及page-size,父组件只是负责初始化赋值,后期操作主要是elementUI,触发了update事件给了封装好的组件,组件再把update事件传递到了父组件,父组件修改该值。
3. 父组件 #
3.1 父组件 template 中的调用 #
xml
<!-- 分页 -->
<PenkFooter
:total="paginationData.total"
v-model:pageNum="paginationData.pageNum"
v-model:pageSize="paginationData.pageSize"
@change="getList"
></PenkFooter>
1
2
3
4
5
6
7
2
3
4
5
6
7
可以看到,就配置了上述的4个属性即可。
3.2 父组件 script 中的调用 #
这边用一个对象 paginationData,存放分页组件的数据,pageNum以及pageSize是双向数据绑定,所以不需要怎么操作,直接调用即可; {
pageNum: paginationData.pageNum,
pageSize: paginationData.pageSize,
}
total的话也只是需要每次根据条件查询,后端返回的总数据量,更新上去即可~~~ paginationData.total = res.count;
代码如下:
typescript
// 表格数据
let tableData = reactive([]);
// 分页数据
const paginationData = reactive({
total: 100,
pageNum: 1,
pageSize: 10,
});
// 查找数据
async function getList() {
// 清空数据
tableData.length = 0;
console.log("tableData1:", tableData);
// 判断是否有对象,没有的话就自动弄
let res = await http.getList({
...refPenkSearch.value.queryObj,
pageNum: paginationData.pageNum,
pageSize: paginationData.pageSize,
});
// @ts-ignore
tableData.push(...res.rows);
paginationData.total = res.count;
console.log("tableData:", tableData);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
tips:这边要注意reactive 创建的tabelData,不能使用直接赋值,因为是个proxy对象~
4. 组件的封装 #
双向数据绑定,这里使用了 v-model 语法糖,拆分开就是 v-bind绑定数据,负责传值;@update:xxx的监听事件,负责通知调用者更新值。
如果组件都是自己写的,完全可以用provide,inject来处理,但是,用了第三方的elementUI组件,所以比较繁琐。
- v-bind:父组件=>封装组件=>elementUI组件 已经打通
- @update:elementUI组件=>封装组件,封装组件=>父组件 打通。
- 封装组件 => 父组件还没打通! 需要监听封装组件中中间件,接收到了elementUI组件的update事件,再将事件传递到父组件。
- 并且父组件传递过去的props 是不能作为 封装组件的v-model 属性传递给elementUI组件的,所以这边还需要一个临时变量用于存储值。
4.1 封装组件template #
typescript
// 子组件的template
<el-pagination
v-model:current-page="paginationData.pageNum"
v-model:page-size="paginationData.pageSize"
:page-sizes="[10, 30, 50, 100]"
background
layout="total, sizes, prev, pager, next, jumper"
:total="total"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
/>
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
4.2 封装组件script #
4.2.1 props属性 #
typescript
// 子组件的script
// 暴露props
interface props {
// 总条目数
total: number;
// 当前页
pageNum: number;
// 页数
pageSize: number;
}
const props = defineProps<props>();
let paginationData = reactive({
pageNum: props.pageNum,
pageSize: props.pageSize,
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
4.2.2 监听elementUI事件,并且触发update事件给父组件 #
typescript
// 子组件的script
import { ref, reactive, watch } from "vue";
// 生成事件对象,数组中就是对象名
const emit = defineEmits(["change", "update:pageSize", "update:pageNum"]);
// 事件,如果用v-model 其实不是很需要这数据...
function handleSizeChange(e: number) {
emit("update:pageSize", e);
emit("change", paginationData);
}
function handleCurrentChange(e: number) {
emit("update:pageNum", e);
emit("change", paginationData);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
总结 #
封装很简单,只要将elementUI组件新的值,传递给父组件即可。
组件源码 #
typescript
<!--
* @Author: Penk
* @LastEditors: Penk
* @LastEditTime: 2022-11-29 16:41:36
* @FilePath: \front-master\src\components\public\PenkFooter.vue
* @email: 492934056@qq.com
-->
<template>
<div class="penk-footer">
<el-pagination
:total="total"
v-model:current-page="paginationData.pageNum"
v-model:page-size="paginationData.pageSize"
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:page-sizes="[10, 30, 50, 100]"
background
layout="total, sizes, prev, pager, next, jumper"
/>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, watch } from "vue";
// 暴露props
interface props {
// 总条目数
total: number;
// 当前页
pageNum: number;
// 页数
pageSize: number;
}
const props = defineProps<props>();
let paginationData = reactive({
pageNum: props.pageNum,
pageSize: props.pageSize,
});
// 生成事件对象,数组中就是对象名
const emit = defineEmits(["change", "update:pageSize", "update:pageNum"]);
// 事件,如果用v-model 其实不是很需要这数据...
function handleSizeChange(e: number) {
emit("update:pageSize", e);
emit("change", paginationData);
}
function handleCurrentChange(e: number) {
emit("update:pageNum", e);
emit("change", paginationData);
}
</script>
<style lang="less" scoped>
.penk-footer {
margin-top: 20px;
float: right;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61