本人是一个web前端开发工程师,主要是vue框架,整理了一些Vue常用的技术,一方面是分享,一方面是做总结,今后也会一直更新,有好建议的同学欢迎评论区分享 ;-)
Vue专栏:点击此处
Vue组件库专栏:点击此处
Vue2 vs Vue3 专栏:点击此处
Typescript专栏:点击此处
Vue组件库专栏会按顺序执行一下流程,不断完善组件库开发流程
环境状态
vue版本:vue3
是否使用 ts:是
后台管理系统的网站,一个页面无非就是4个常用业务块
那咋们是不是可以将其进行封装成组件呢?
只需要传入一个配置文件就可以了~
项目解构如下:
封装后的展示图如下:
效果图如下:
如果能做成这样,是不是页面就会整洁很多?
一个管理系统的分页基本上样式以及布局都是一样的,不然也没必要封装一层,这边主要需要3个属性,以及1个事件。
- total 传递数据总数量,这个是单向数据流,是后台返回的数据量
- pageNum传递当前页码,这个是需要双向绑定的,因为这个是父组件初始化,后期根据用户操作 elementUI 返回新的页码,这个主要用于后台请求数据的一个参数。
- pageSize传递当前一页的大小,这个是需要双向绑定的,因为这个是父组件初始化,后期根据用户操作 elementUI 返回新的页码,这个主要用于后台请求数据的一个参数。
- 监听pageNum,pageSize的change事件,虽然也可以在父组件通过watch监听变量,不过那样代码就比较多了,可以直接监听change事件,触发就直接调用自定义的请求数据接口getList…
element-plus官网
从中可以看出:
<PenkFooter
:total="paginationData.total"
v-model:pageNum="paginationData.pageNum"
v-model:pageSize="paginationData.pageSize"
@change="getList"
>PenkFooter>
可以看到,就配置了上述的4个属性即可。
这边用一个对象 paginationData,存放分页组件的数据,pageNum以及pageSize是双向数据绑定,所以不需要怎么操作,直接调用即可;
{
pageNum: paginationData.pageNum,
pageSize: paginationData.pageSize,
}
total的话也只是需要每次根据条件查询,后端返回的总数据量,更新上去即可~~~
paginationData.total = res.count;
代码如下:
// 表格数据
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);
}
tips:这边要注意reactive 创建的tabelData,不能使用直接赋值,因为是个proxy对象~
双向数据绑定,这里使用了 v-model 语法糖,拆分开就是 v-bind绑定数据,负责传值;@update:xxx的监听事件,负责通知调用者更新值。
如果组件都是自己写的,完全可以用provide,inject来处理,但是,用了第三方的elementUI组件,所以比较繁琐。
// 子组件的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"
/>
// 子组件的script
// 暴露props
interface props {
// 总条目数
total: number;
// 当前页
pageNum: number;
// 页数
pageSize: number;
}
const props = defineProps<props>();
let paginationData = reactive({
pageNum: props.pageNum,
pageSize: props.pageSize,
});
// 子组件的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);
}
封装很简单,只要将elementUI组件新的值,传递给父组件即可。
<!--
* @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>