当前位置: 首页 > news >正文

Vue3手写分页器

在学习电商项目时,有一个手写分页器的功能模块,但是使用Vue2实现的,所以用Vue3尝试着写了一个。

首先,有四个点要了解

1)分页器展示,需要哪些数据(条件)?

  • 当前是第几个: pageNo字段表示当前页数

  • 每一页需要展示多少条数据:pageSize字段

  • 整个分页器一共有多少条数据: total字段 —— 【一共多少页: total/pageSize,向上取整】

  • 分页器连续页码个数,一般是5或者7: continues字段

2)自定义分页器,在开发的时候先自己传递假的数据进行调试,调试成功再用服务器数据

3)对于分页器而言,很重要的一个地方是 【算出:连续页码起始数字和结束数字】

当前如果是第8页且连续页码数为5,则为 6 7 8 9 10。但还需要兼顾到特殊情况(如起始页不能小于1,结束页不能超过总页数,以及连续页码数必须要小于总页数),否则就要特别的赋值

4)分页器动态展示

v-for: 可以遍历 数组|数字|字符串|对象

然后开始正式写代码。分页器的组件名为PaginationIndex,在搜索页SearchIndex使用该组件。

静态页面

首先,找一个分页器的静态界面,先把它展示出来,之后再做各功能的添加

<template>
  <div class="pagination">
    <button>1</button>
    <button>上一页</button>
    <button>···</button>

    <button>3</button>
    <button>4</button>
    <button>5</button>
    <button>6</button>
    <button>7</button>
    
    <button>···</button>
    <button>9</button>
    <button>上一页</button>
    
    <button style="margin-left: 30px">共 60 条</button>
  </div>
</template>

<script>
  export default {
    name: "PaginationIndex",
  }
</script>

<style lang="less" scoped>
  .pagination {
    button {
      margin: 0 5px;
      background-color: #f4f4f5;
      color: #606266;
      outline: none;
      border-radius: 2px;
      padding: 0 4px;
      vertical-align: top;
      display: inline-block;
      font-size: 13px;
      min-width: 35.5px;
      height: 28px;
      line-height: 28px;
      cursor: pointer;
      box-sizing: border-box;
      text-align: center;
      border: 0;

      &[disabled] {
        color: #c0c4cc;
        cursor: not-allowed;
      }

      &.active {
        cursor: not-allowed;
        background-color: #409eff;
        color: #fff;
      }
    }
  }
</style>

 因为数据,页数都是自己写死的,所以接下来需要获得我们真正所需要的数据(需要从父组件中传过来)

 SearchIndex中使用该组件时,传递相应的值

           <!-- 分页器 测试分页器阶段-->
          <PaginationIndex
            :pageNo="1"
            :pageSize="10"
            :total="91"
            :continues="5"
          />

父元素给子元素传递数据,这里采用props接收。 子组件中

export default {
  name: "PaginationIndex",
  props: ["pageNo", "pageSize", "total", "continues"],

分页器起始与结束——计算属性

同时,应该根据pageNo(当前所在页),计算出它的前后连续页(这里因为continues=5,也就是前后连续5页)。这里使用计算属性,分别用了两种方法。

这里的计算属性因为自己用的不是很熟练,可能写的有点繁琐或者不太对的地方,有问题的地方大佬看到了可以教教我。

setup(props, context) {
    const PageInfo = reactive({});

    // 总共多少页
    (PageInfo.totalPage = computed({
      get() {
        return Math.ceil(props.total / props.pageSize);
      },
    })),
      // 计算出连续的页码的起始数字和结束数字【最少5页】
      (PageInfo.startNumAndEndNum = computed(() => {
        const { pageNo, pageSize, total, continues } = props;
        // 定义两个变量,存储起始与结束 数字
        let start = 0;
        let end = 0;
        // 连续页码数字5 【至少为5页】,如果没有5页
        if (continues > PageInfo.totalPage) {
          start = 1;
          end = PageInfo.totalPage;
        } else {
          // 总页数 > 连续页数
          start = pageNo - Math.floor(continues / 2);
          end = start + continues - 1;
          // 把不正常的现象纠正,比如start小于1,或者end超过total了
          if (start < 1) {
            start = 1;
            end = continues;
          }
          if (end > PageInfo.totalPage) {
            end = PageInfo.totalPage;
            start = PageInfo.totalPage - continues + 1;
          }
        }
        return { start, end };
      }));

计算连续页数这里要考虑算法健壮性,比如连续页码数比总页数还大的情况,或者通过计算后,连续起始页小于1,连续结束页大于总页数。 这里返回以对象形式返回

不仅如此,还要考虑到如果起始页为1,上一页功能应该禁用,结束页到底了,下一页按钮也要禁用。还有如果起始页为2,1后面的省略号就不需要了。 

DOM结构的代码如下:

<template>
  <div class="pagination">
    <button :disabled="pageNo == 1">
      上一页
    </button>
    <button
      v-show="PageInfo.startNumAndEndNum.start > 1"
    >
      1
    </button>

    <button v-if="PageInfo.startNumAndEndNum.start > 2">···</button>

    <button
      v-for="(page, index) in continues"
      :key="index"
    >
      {{ page + PageInfo.startNumAndEndNum.start - 1 }}
    </button>

    <button v-if="PageInfo.startNumAndEndNum.end < PageInfo.totalPage - 1">
      ···
    </button>
    <button
      v-show="PageInfo.startNumAndEndNum.end < PageInfo.totalPage"
    >
      {{ PageInfo.totalPage }}
    </button>
    <button :disabled="pageNo == PageInfo.totalPage">下一页</button>

    <button style="margin-left: 30px">共 {{ total }} 条</button>
  </div>
</template>

 这里和vue2里有个小区别就是,vue2中之前的代码里 v-for循环展示中间连续页时,v-for和v-if一起用的。v-for可以循环遍历数字,所以vue2里面是v-for的结束页,假设结束页是10,也就是连续页码为6 7 8 9 10,v-for="(page,index) in PageInfo.startNumAndEndNum.end",这里就会遍历10次,vue2中的做法是,加上v-if判断,只保留后面的5次。但是vue3里面v-for和v-if没法放一起用。所以我的想法是,要么外面包一层div,给外层div加上v-if。我这就是采用v-for 连续页数。也就是只遍历5次,page就是从1-5,然后展示的时候只需要page + 起始页 - 1即为对应的连续页。

 分页器动态展示

将分页器按照需求改好后,页面部分就算是差不多了,接下来需要点击相应的页码,进行相应数据的改动以及重新发送请求。这里就涉及到子组件给父组件传递数据,所以采用自定义事件

vue3中自定义事件相关的记录写在了下面这个博客里

https://blog.csdn.net/m0_56698268/article/details/126578810

 中间等等过程就先不写了。最后放上分页器组件的代码

PaginationIndex.vue

<template>
  <div class="pagination">
    <button :disabled="pageNo == 1" @click="getPageNo(pageNo - 1)">
      上一页
    </button>
    <button
      v-show="PageInfo.startNumAndEndNum.start > 1"
      @click="getPageNo(1)"
      :class="{ active: pageNo == 1 }"
    >
      1
    </button>

    <button v-if="PageInfo.startNumAndEndNum.start > 2">···</button>

    <button
      v-for="(page, index) in continues"
      :key="index"
      @click="getPageNo(page + PageInfo.startNumAndEndNum.start - 1)"
      :class="{ active: pageNo == page + PageInfo.startNumAndEndNum.start - 1 }"
    >
      {{ page + PageInfo.startNumAndEndNum.start - 1 }}
    </button>

    <button v-if="PageInfo.startNumAndEndNum.end < PageInfo.totalPage - 1">
      ···
    </button>
    <button
      v-show="PageInfo.startNumAndEndNum.end < PageInfo.totalPage"
      @click="getPageNo(PageInfo.totalPage)"
      :class="{ active: pageNo == PageInfo.totalPage }"
    >
      {{ PageInfo.totalPage }}
    </button>
    <button :disabled="pageNo == PageInfo.totalPage">下一页</button>

    <button style="margin-left: 30px">共 {{ total }} 条</button>
  </div>
</template>

<script>
import { computed, reactive } from "vue";

export default {
  name: "PaginationIndex",
  props: ["pageNo", "pageSize", "total", "continues"],
  emits: ["getPageNo"],
  setup(props, context) {
    const PageInfo = reactive({});

    // 总共多少页
    (PageInfo.totalPage = computed({
      get() {
        return Math.ceil(props.total / props.pageSize);
      },
    })),
      // 计算出连续的页码的起始数字和结束数字【最少5页】
      (PageInfo.startNumAndEndNum = computed(() => {
        const { pageNo, pageSize, total, continues } = props;
        // 定义两个变量,存储起始与结束 数字
        let start = 0;
        let end = 0;
        // 连续页码数字5 【至少为5页】,如果没有5页
        if (continues > PageInfo.totalPage) {
          start = 1;
          end = PageInfo.totalPage;
        } else {
          // 总页数 > 连续页数
          start = pageNo - Math.floor(continues / 2);
          end = start + continues - 1;
          // 把不正常的现象纠正,比如start小于1,或者end超过total了
          if (start < 1) {
            start = 1;
            end = continues;
          }
          if (end > PageInfo.totalPage) {
            end = PageInfo.totalPage;
            start = PageInfo.totalPage - continues + 1;
          }
        }
        return { start, end };
      }));
    function getPageNo(pageNo) {
      context.emit("getPageNo", pageNo);
    }
    return {
      PageInfo,
      getPageNo,
    };
  },
};
</script>

<style lang="less" scoped>
.pagination {
  text-align: center;
  button {
    margin: 0 5px;
    background-color: #f4f4f5;
    color: #606266;
    outline: none;
    border-radius: 2px;
    padding: 0 4px;
    vertical-align: top;
    display: inline-block;
    font-size: 13px;
    min-width: 35.5px;
    height: 28px;
    line-height: 28px;
    cursor: pointer;
    box-sizing: border-box;
    text-align: center;
    border: 0;

    &[disabled] {
      color: #c0c4cc;
      cursor: not-allowed;
    }

    &.active {
      cursor: not-allowed;
      background-color: #409eff;
      color: #fff;
    }
  }
}
.active {
  background-color: skyblue;
}
</style>

父组件 SearchIndex.vue

DOM
        <!-- 分页器 测试分页器阶段-->
          <PaginationIndex
            :pageNo="searchParams.pageNo"
            :pageSize="searchParams.pageSize"
            :total="total"
            :continues="5"
            @getPageNo="getPageNo"
          />

JS
export default {
  name: "SearchIndex",
  components: {
    SearchSelector,
  },
  setup() {
    const store = useStore();
    const $route = useRoute();
    const $router = useRouter();
    const internalInstance = getCurrentInstance();
    const $bus = internalInstance.appContext.config.globalProperties.$bus;
    // 带给服务器的参数
    const searchParams = reactive({
      // 一级分类id
      category1Id: "",
      // 二级分类id
      category2Id: "",
      // 三级分类id
      category3Id: "",
      // 分类名字
      categoryName: "",
      // 关键字
      keyword: "",
      // 排序 : 初始状态应该是综合|降序
      order: "1:desc",
      // 分页器
      pageNo: 1,
      // 每页展示数据个数
      pageSize: 10,
      // 平台售卖属性操作带的参数
      props: [],
      // 品牌
      trademark: "",
    });
    let total = computed({
      get() {
        return store.state.search.searchList.total;
      },
    });
    // 自定义事件回调——获取当前第几页
    function getPageNo(pageNo) {
      // console.log("getPageNo", pageNo);
      // 整理带给服务器参数
      searchParams.pageNo = pageNo;
      getData();
    }

相关文章:

  • Apache,PHP安装及Apache引入PHP模块
  • chosen.jquery.js 插件的使用和总结
  • 全网最牛自动化测试框架系列之pytest(9)-标记用例(指定执行、跳过用例、预期失败)
  • ARM汇编
  • Docker部署并启动RabbitMQ
  • 树莓派远程音乐播放器
  • LeetCode用数组建立二叉树
  • Leetcode560. 和为 K 的子数组
  • Docker部署Tomcat
  • NFT交易量下滑 传统品牌布局热情未衰
  • 2022下半年各省软考报名费用汇总,不知道的看这里
  • 社交网络的数据挖掘与分析,什么是社交网络分析
  • Allegro DVT与SiMa.ai携手优化嵌入式边缘应用的能效
  • 2022-8-30 第七小组 学习日记 (day54)JavaWeb、Servlet、HTTP-请求 响应、乱码问题
  • U9二次开发之BE插件开发
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • FineReport中如何实现自动滚屏效果
  • Java反射-动态类加载和重新加载
  • JS数组方法汇总
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • Spring Cloud中负载均衡器概览
  • 技术发展面试
  • 简单基于spring的redis配置(单机和集群模式)
  • 力扣(LeetCode)56
  • 入门到放弃node系列之Hello Word篇
  • 系统认识JavaScript正则表达式
  • 小程序01:wepy框架整合iview webapp UI
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 第二十章:异步和文件I/O.(二十三)
  • 直播平台建设千万不要忘记流媒体服务器的存在 ...
  • #常见电池型号介绍 常见电池尺寸是多少【详解】
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (02)vite环境变量配置
  • (C语言)球球大作战
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (六)vue-router+UI组件库
  • (论文阅读23/100)Hierarchical Convolutional Features for Visual Tracking
  • (三)uboot源码分析
  • (十)DDRC架构组成、效率Efficiency及功能实现
  • (一)appium-desktop定位元素原理
  • (原创)boost.property_tree解析xml的帮助类以及中文解析问题的解决
  • (转)Scala的“=”符号简介
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .NET Core 版本不支持的问题
  • .NET 分布式技术比较
  • .net 无限分类
  • .NET/C# 检测电脑上安装的 .NET Framework 的版本
  • /etc/sudoer文件配置简析
  • @manytomany 保存后数据被删除_[Windows] 数据恢复软件RStudio v8.14.179675 便携特别版...
  • [ C++ ] STL_stack(栈)queue(队列)使用及其重要接口模拟实现
  • [ vulhub漏洞复现篇 ] Hadoop-yarn-RPC 未授权访问漏洞复现
  • [ 常用工具篇 ] AntSword 蚁剑安装及使用详解
  • [AX]AX2012 SSRS报表Drill through action