首页 > 其他分享 >总结 vue 实现分页器的基本思路

总结 vue 实现分页器的基本思路

时间:2022-10-19 11:34:51浏览次数:65  
标签:newPage vue 分页 color start totalPages currentPage 基本思路 页码

简介

本文介绍基于 vue2 框架实现基本的分页器,包括页码前进/后退、页码点击跳转、显示 ... 、显示总页数、显示总数据条数 等功能。

效果预览

快速跳转

视图部分样式部分数据部分逻辑处理部分

实现思路

视图部分

视图方面比较简单,将各功能部分依次搭建即可,包括前进键(>>)、后退键(<<)、中间以及首尾(1和页码上限)的页码、...、以及页码总计和数据总计。

代码示例

<template>
  <div class="pagination">
    <div class="pagination_wrap">
      <div class="pagination_total-data pagination_info">
        <span>共{{ total }}条数据</span>
      </div>
      <div class="pagination_action-group">
        <div
          class="prev pagination_btn"
          :class="{ disabled: isPrevDisabled }"
          :disabled="isPrevDisabled"
          @click="handlePrev"
        >
          <a>«上一页</a>
        </div>
        <div class="pagination_btn-group" @click="handlePageSelect">
          <template v-if="isShowPrevDot">
            <li class="pagination_btn">
              <a data-page="1">1</a>
            </li>
            <li class="pagination_dotted">
              <span>...</span>
            </li>
          </template>
          <li
            class="pagination_btn"
            :class="{ active: currentPage === i }"
            v-for="i in pageList"
            :key="i"
          >
            <a :data-page="i">{{ i }}</a>
          </li>
          <template v-if="isShowNextDot">
            <li class="pagination_dotted">
              <span>...</span>
            </li>
            <li class="pagination_btn">
              <a :data-page="totalPages">{{ totalPages }}</a>
            </li>
          </template>
        </div>
        <div
          class="next pagination_btn"
          :class="{ disabled: isNextDisabled }"
          :disabled="isNextDisabled"
          @click="handleNext"
        >
          <a>下一页»</a>
        </div>
      </div>
      <div class="pagination_total-pages pagination_info">
        <span>共{{ totalPages }}页</span>
      </div>
    </div>
  </div>
</template>

样式部分

样式部分(scss),通过 Flex 布局使元素水平排列,并赋予基本样式

// 全局 css 变量
:root {
  --gap-small: 5px;
  --gap-primary: 15px;
}

// 覆盖浏览器默认样式
body {
  li {
    box-sizing: border-box;
  }
  // 注意添加下面这条样式,否则部分浏览器在 ... 旁边会显示一个额外的 ·
  [class*='dotted']::marker {
    content: '';
  }
}

.pagination {
  width: 100%;
  overflow: hidden;

  .pagination_wrap {
    margin: 18px 0;
    display: flex;
    justify-content: center;

    .pagination_action-group {
      margin-left: 0;
      margin-bottom: 0;
      vertical-align: middle;
      display: flex;

      .pagination_btn {
        line-height: 18px;
        display: inline-block;

        a {
          position: relative;
          line-height: 18px;
          text-decoration: none;
          background-color: #fff;
          border: 1px solid #e0e9ee;
          font-size: 14px;
          padding: 9px 18px;
          color: #333;
        }

        &.active {
          a {
            background-color: #fff;
            color: #e1251b;
            border-color: #fff;
            cursor: default;
          }
        }

        &.prev,
        &.next {
          a {
            background-color: #fafafa;
            cursor: pointer;
          }
        }

        &.disabled {
          a {
            color: #999;
            cursor: default;
          }
        }
      }

      .pagination_dotted {
        span {
          position: relative;
          line-height: 18px;
          text-decoration: none;
          background-color: #fff;
          font-size: 14px;
          border: 0;
          padding: 9px 18px;
          color: #333;
        }
      }

      .pagination_btn-group {
        display: flex;
      }
    }

    .pagination_info {
      color: #333;
      font-size: 14px;
    }

    .pagination_total-data {
      margin-right: var(--gap-primary);
    }

    .pagination_total-pages {
      margin-left: var(--gap-primary);
    }
  }
}

数据和逻辑

接下里是关键的逻辑实现,包括前进、后退、页码点选跳转、显示 ... 等功能。

数据部分

props 中定义的 4 个变量与数据显示相关,通常从服务端获取,且不支持内部修改,因此由父组件传递进来;data 和 computed 中定义的 8 个变量与视图构建或更新相关,属于组件内私有,仅支持内部修改。

props: {
  total: Number, // 数据总数
  currentPage: Number, // 当前页码数
  pagerCount: Number, // 允许同时显示的页码数
  totalPages: Number, // 页码总数
},
data() {
  return {
    pageList: [], // 中间区域显示的页码范围
    start: 0, // 中间区域显示的开始页码指针
    end: 0, // 中间区域显示的结束页码指针
    isShowPrevDot: false,
    isShowNextDot: false,
  };
},
computed: {
  isPrevDisabled() {
    return this.currentPage === 1;
  },
  isNextDisabled() {
    return this.currentPage === this.totalPages;
  },
  // 总页数超过当前允许的同时显示页数,才有可能需要显示 ...
  isDotNeeded() {
    return this.totalPages > this.pagerCount;
  },
},

逻辑处理部分

逻辑处理部分包括:

  • 两个内部变量更新方法:setupPageList(start, end) 和 setupPagination(currentPage, totalPages, pagerCount)
  • 一个 emit 通知方法:updateCurrentPage(newPage)
  • 三个事件处理方法:handlePrev() 、handleNext() 、handlePageSelect(e)
  • 一个侦听器:侦听 currentPage 并初始化
methods: {
  // 根据开始和结束指针,重新生成中间区域的页码
  setupPageList(start, end) {
    let pageList = [];
    for (let i = start; i <= end; i++) {
      pageList.push(i);
    }
    return pageList;
  },
  // 根据操作后的当前页码,重新判定是否显示两侧的 ... ,以及更新中间区域的页码范围
  setupPagination(currentPage, totalPages, pagerCount) {
    // 初始化 start 和 end
    let start = 1, end = totalPages;
    if (this.isDotNeeded) {
      // 从当前页码开始,向左右两侧延伸 pagerCount 一半的距离
      let halfOffset= Math.floor(pagerCount / 2, 0);
      start = Math.max(1, currentPage - halfOffset);
      end = Math.min(totalPages, currentPage + halfOffset);
      // 若中间页码数量仍小于 pagerCount,先拉长到 pagerCount
      if (end - start + 1 < pagerCount) {
        if (end - pagerCount > -1) {
          // 左侧仍有剩余页码
          start = end - pagerCount + 1;
        } else {
          end = start + pagerCount - 1;
        }
      }
      // 根据延伸后的左右指针,判定是否需要显示左右两侧的 ...
      this.isShowPrevDot = start > 1;
      this.isShowNextDot = totalPages - end > 0;
    } else {
      this.isShowPrevDot = false;
      this.isShowNextDot = false;
    }
    // 根据 ... 的判定结果,赋值两侧指针的最终值
    this.start = Math.max(1, start + (this.isShowPrevDot ? 1 : 0));
    this.end = Math.min(totalPages, end - (this.isShowNextDot ? 1 : 0));
    // 根据最新的指针,生成中间区域的页码
    this.pageList = [].concat(this.setupPageList(this.start, this.end));
  },
  handlePrev() {
    const oldPage = this.currentPage;
    const newPage = Math.max(1, oldPage - 1);
    if (oldPage !== newPage) {
      this.updateCurrentPage(newPage);
      // 由于侦听器的存在,不需要手动触发分页器更新;next 与 select 同理
      // this.setupPagination(newPage);
    }
  },
  handleNext() {
    const oldPage = this.currentPage;
    const newPage = Math.min(this.totalPages, oldPage + 1);
    if (oldPage !== newPage) {
      this.updateCurrentPage(newPage);
    }
  },
  handlePageSelect(e) {
    const newPage = +e.target.dataset.page;
    this.updateCurrentPage(newPage);
  },
  // 通知父组件修改当前页
  updateCurrentPage(newPage) {
    this.$emit('updateCurrentPage', newPage);
  },
},
// 由于数据从服务端获取,需要在当前组件或作为父组件的业务组件中监听初始数据的变化,并触发分页器的初始化
// 同时,用户改变当前页码时,也会触发分页器更新
watch: {
  currentPage: {
    immediate: true,
    handler() {
      this.$nextTick(() => {
        this.setupPagination(
          this.currentPage,
          this.totalPages,
          this.pagerCount
        );
      });
    },
  },
},

标签:newPage,vue,分页,color,start,totalPages,currentPage,基本思路,页码
From: https://www.cnblogs.com/cjc-0313/p/16805657.html

相关文章

  • 分页 模糊查询
     serversql分页查询,按匹配精准度排序SELECTS_INFO_WINDCODE,S_INFO_CODE,S_INFO_NAME,S_INFO_COMPNAME,S_INFO_COMPNAMEENG,S_INFO_EXC......
  • Vue使用keep-alive后,el-tooltip悬浮内容在切换页面时不自动消失
    试过在deactivated()和App.vue里改,都无效。有用的方法:在第二个页面中判断是否有这个元素,手动移除;beforeCreate(){constdom=document.querySelect......
  • vue-element-admin 安装报错解决办法
    1.克隆以后删除package.json中tui-editor:1.3.32.\src\components\MarkdownEditor\index.vue文件,将全部import换成下面几个import'codemirror/lib/codemirror.css'impor......
  • 我的Vue之旅 07 Axios + Golang + Sqlite3 实现简单评论机制
    第三期·使用Vue3.1+TailWind.CSS+Axios+Golang+Sqlite3实现简单评论机制效果图CommentArea.vue我们需要借助js的Data对象把毫秒时间戳转化成UTCStrin......
  • vue 文件打包太大 -- 体积优化
    最新打包vuecli4.5项目时,体积尽然达到了9M,页面访问的速度,因此进行尝试进行优化,最终压缩到968k,效果明显。下面是优化方法。首先新建文件'vue.config.js',放在项目根目......
  • vue之axios
    什么是axios?Axios是一个基于promise的HTTP库,可以用在浏览器和node.js中。特性1从浏览器中创建XMLHttpRequests2从node.js创建http请求3支持PromiseAPI4......
  • 黑马瑞吉外卖之套餐信息的分页查询
    黑马瑞吉外卖之套餐信息的分页查询​​表和实体类环境以及前端页面分析​​​​后端代码的逻辑开发​​表和实体类环境以及前端页面分析首先这里是套餐的功能开发,我们在设置......
  • 【Vue】图片拉近、全屏背景实战经验总结
    1图片拉近缘起是看到了下面的图片,我发现当鼠标悬浮的时候,发现他是可以拉近的,也就是图片的宽高不变,但是图片被放大了起初我以为是有一个这样的方法,可以实现这个操作,但是查找......
  • 从0搭建vue3组件库:Shake抖动组件
    先看下效果其实就是个抖动效果组件,实现起来也非常简单。之所以做这样一个组件是为了后面写Form表单的时候会用到它做一个规则校验,比如下面一个简单的登录页面,当点击登录......
  • vue组件通信6种方式总结(常问知识点)
    前言在Vue组件库开发过程中,Vue组件之间的通信一直是一个重要的话题,虽然官方推出的Vuex状态管理方案可以很好的解决组件之间的通信问题,但是在组件库内部使用Vuex往往会......