Vue3+ts+element-plus 组件的二次封装-- 页脚分页el-pagination的二次封装

Vue 笔记

本人是一个web前端开发工程师,主要是vue框架,整理了一些Vue常用的技术,一方面是分享,一方面是做总结,今后也会一直更新,有好建议的同学欢迎评论区分享 ;-)

Vue专栏:点击此处
Vue组件库专栏:点击此处
Vue2 vs Vue3 专栏:点击此处
Typescript专栏:点击此处

Vue3+ts+element-plus 组件的二次封装-- 页脚分页el-pagination的二次封装_第1张图片


组件库开发流程

Vue组件库专栏会按顺序执行一下流程,不断完善组件库开发流程

  1. Vue3+element-plus+vite 组件的二次封装,封装了头部的搜索条件栏,tabel栏,分页栏,form表单,都设置成了通过json可配置项,方便复用;
  2. 封装好了就开始打包,并且进行本地测试;
  3. 组件库发布到npm;
  4. 添加vitest单元测试框架;
  5. 添加vuepress文档。

文章目录

  • Vue 笔记
  • 组件库开发流程
  • 前言
  • 需求分析
  • 分页el-pagination的二次封装分析
    • 1. 效果图
    • 2. 查看elementUI组件的配置
    • 3. 父组件
      • 3.1 父组件 template 中的调用
      • 3.2 父组件 script 中的调用
    • 4. 组件的封装
      • 4.1 封装组件template
      • 4.2 封装组件script
        • 4.2.1 props属性
        • 4.2.2 监听elementUI事件,并且触发update事件给父组件
  • 总结
  • 组件源码


前言

环境状态
vue版本:vue3
是否使用 ts:是

后台管理系统的网站,一个页面无非就是4个常用业务块

  1. 头部的搜索栏
  2. table表格
  3. 页脚
  4. 新增编辑弹框

那咋们是不是可以将其进行封装成组件呢?
只需要传入一个配置文件就可以了~

项目解构如下:
在这里插入图片描述

封装后的展示图如下:
在这里插入图片描述

效果图如下:

在这里插入图片描述

如果能做成这样,是不是页面就会整洁很多?


需求分析

一个管理系统的分页基本上样式以及布局都是一样的,不然也没必要封装一层,这边主要需要3个属性,以及1个事件。

  1. total 传递数据总数量,这个是单向数据流,是后台返回的数据量
  2. pageNum传递当前页码,这个是需要双向绑定的,因为这个是父组件初始化,后期根据用户操作 elementUI 返回新的页码,这个主要用于后台请求数据的一个参数。
  3. pageSize传递当前一页的大小,这个是需要双向绑定的,因为这个是父组件初始化,后期根据用户操作 elementUI 返回新的页码,这个主要用于后台请求数据的一个参数。
  4. 监听pageNum,pageSize的change事件,虽然也可以在父组件通过watch监听变量,不过那样代码就比较多了,可以直接监听change事件,触发就直接调用自定义的请求数据接口getList…

分页el-pagination的二次封装分析

1. 效果图

Vue3+ts+element-plus 组件的二次封装-- 页脚分页el-pagination的二次封装_第2张图片


2. 查看elementUI组件的配置

element-plus官网

Vue3+ts+element-plus 组件的二次封装-- 页脚分页el-pagination的二次封装_第3张图片

从中可以看出:

  1. 单向数据流total,是用来展示总共有多少条数据的,主要从父组件=>封装子组件=>elementUI组件,主要是由父组件控制。
  2. 双向数据绑定current-page,以及page-size,分别代表当前页码以及每一页的数据量。
  3. current-page,以及page-size,父组件只是负责初始化赋值,后期操作主要是elementUI,触发了update事件给了封装好的组件,组件再把update事件传递到了父组件,父组件修改该值。

Vue3+ts+element-plus 组件的二次封装-- 页脚分页el-pagination的二次封装_第4张图片


3. 父组件

3.1 父组件 template 中的调用


<PenkFooter
  :total="paginationData.total"
  v-model:pageNum="paginationData.pageNum"
  v-model:pageSize="paginationData.pageSize"
  @change="getList"
>PenkFooter>

可以看到,就配置了上述的4个属性即可。


3.2 父组件 script 中的调用

这边用一个对象 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对象~


4. 组件的封装

双向数据绑定,这里使用了 v-model 语法糖,拆分开就是 v-bind绑定数据,负责传值;@update:xxx的监听事件,负责通知调用者更新值。

如果组件都是自己写的,完全可以用provide,inject来处理,但是,用了第三方的elementUI组件,所以比较繁琐。

  1. v-bind:父组件=>封装组件=>elementUI组件 已经打通
  2. @update:elementUI组件=>封装组件,封装组件=>父组件 打通。
  3. 封装组件 => 父组件还没打通! 需要监听封装组件中中间件,接收到了elementUI组件的update事件,再将事件传递到父组件。
  4. 并且父组件传递过去的props 是不能作为 封装组件的v-model 属性传递给elementUI组件的,所以这边还需要一个临时变量用于存储值。

vue官网
Vue3+ts+element-plus 组件的二次封装-- 页脚分页el-pagination的二次封装_第5张图片


4.1 封装组件template

// 子组件的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"
/>

4.2 封装组件script

4.2.1 props属性

// 子组件的script
// 暴露props
interface props {
  // 总条目数
  total: number;
  // 当前页
  pageNum: number;
  // 页数
  pageSize: number;
}
const props = defineProps<props>();

let paginationData = reactive({
  pageNum: props.pageNum,
  pageSize: props.pageSize,
});

4.2.2 监听elementUI事件,并且触发update事件给父组件

// 子组件的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>

你可能感兴趣的:(vue组件封装,vue.js,javascript,前端)