分页功能组件封装

284 阅读1分钟

分页功能相信大家经常见到,不管是前台页面还是后台管理系统,只要涉及到数据较多的时候,就会用到分页组件。

一、为什么封装?

  • 分页功能使用场景较多,故考虑封装为全局组件
  • 自己封装成本较低,需要什么功能就添加什么功能
  • 相对使用现成组件库,自己封装代码体积可控

二、如何封装?

1. 封装

和之前文章一样的步骤,src/components文件夹下新建my-pagination.vue文件

代码如下(示例):

<template>
  <div class="my-pagination">
    <a @click='changePage(false)' href="javascript:;" :class="{disabled: currentPage===1}">上一页</a>
    <span v-if='currentPage > 3'>...</span>
    <a @click='changePage(item)' href="javascript:;" :class='{active: currentPage===item}' v-for='item in list' :key='item'>{{item}}</a>
    <span v-if='currentPage < pages - 2'>...</span>
    <a @click='changePage(true)' href="javascript:;" :class='{disabled: currentPage===pages}'>下一页</a>
  </div>
</template>
<script>
import { computed, ref } from 'vue'

export default {
  name: 'MyPagination',
  props: {
    total: {
      type: Number,
      default: 80
    },
    pagesize: {
      type: Number,
      default: 10
    }
    // 默认初始页码
    // page: {
    //   type: Number,
    //   default: 1
    // }
  },
  setup (props, { emit, attrs }) {
    // attrs表示父组件传递的属性,但是props没有接收的属性,这种属性不是响应式的
    // 动态计算中期的页码信息
    // 每页的条数
    // const pagesize = 8
    // 总页数
    const pages = computed(() => Math.ceil(props.total / props.pagesize))
    // 当前页码
    // console.log(attrs.page)
    const currentPage = ref(attrs.page || 1)
    // 动态计算页码列表
    const list = computed(() => {
      // 当父组件传递total的值发生变化时,计算属性会重新计算
      // pages = Math.ceil(props.total / props.pagesize)
      const result = []
      // 总页码小于等于5;大于5
      if (pages.value <= 5) {
        // 总页码小于等于5的情况
        for (let i = 1; i <= pages.value; i++) {
          result.push(i)
        }
      } else {
        // 总页码大于5
        if (currentPage.value <= 2) {
          // 左侧临界值
          for (let i = 1; i <= 5; i++) {
            result.push(i)
          }
        } else if (currentPage.value >= pages.value - 1) {
          // 右侧临界值
          for (let i = pages.value - 4; i <= pages.value; i++) {
            result.push(i)
          }
        } else {
          // 中间的状态
          for (let i = currentPage.value - 2; i <= currentPage.value + 2; i++) {
            result.push(i)
          }
        }
      }
      return result
    })
    // 控制上一页和下一页变化
    const changePage = (type) => {
      if (type === false) {
        // 上一页
        // 页面是第一页时,禁止点击操作
        if (currentPage.value === 1) return
        if (currentPage.value > 1) {
          currentPage.value -= 1
        }
      } else if (type === true) {
        // 下一页
        // 页面是最后页时,禁止点击操作
        if (currentPage.value === pages.value) return
        if (currentPage.value < pages.value) {
          currentPage.value += 1
        }
      } else {
        // 点击页码
        currentPage.value = type
      }
      emit('change-page', currentPage.value)
    }
    return { list, currentPage, pages, changePage }
  }
}
</script>
<style scoped lang="less">
.my-pagination {
  display: flex;
  justify-content: center;
  padding: 30px;
  > a {
    display: inline-block;
    padding: 5px 10px;
    text-decoration: none;
    color: #666;
    border: 1px solid #e4e4e4;
    border-radius: 4px;
    margin-right: 10px;
    &:hover {
      color: #27ba9b;
    }
    &.active {
      background: #27ba9b;
      color: #fff;
      border-color: #27ba9b;
    }
    &.disabled {
      cursor: not-allowed;
      opacity: 0.4;
      &:hover {
        color: #333;
      }
    }
  }
  > span {
    margin-right: 10px;
  }
}
</style>

2. 使用

在任意.vue结尾文件中使用

代码如下(示例): 这里使用固定数据模拟一下

<template>
 <div class="home-container">
   <MyPagination @change-page='changePage' :pagesize='10' :total='80' :page='1' />
 </div>
</template>

<script>
import { reactive } from 'vue'
export default {
  name: 'App',
  setup () {
    // 筛选条件准备
    const reqParams = reactive({
      // 当前页码
      page: 1,
      // 每页的条数
      pageSize: 10
    })
    // 控制页码的变化
    const changePage = (page) => {
      // 修改分页参数,重新调用接口即可
      // console.log(page)
      reqParams.page = page
    }

    return { changePage }
  }

}
</script>

<style lang="less">
.home-container {
  margin: 100px auto;
  width: 1000px;
  height: 100px;
}

</style>

三、效果演示

bb89b604a2774ed39f8ee154126730ef_tplv-k3u1fbpfcp-zoom-in-crop-mark_3024_0_0_0.awebp