vue3 分页组件实现 item动态控制

本文介绍了使用Vue3构建一个可复用的分页导航组件的过程,包括模板结构、逻辑控制和CSS样式。组件通过接收父组件的配置,动态计算并展示页数。在实现过程中,作者强调了逻辑控制的难点,特别是页数数组的更新与状态管理。此外,还分享了使用SCSS的心得,并提出对初学者的建议。
摘要由CSDN通过智能技术生成

1、实现效果
在这里插入图片描述
简述:在日常开发中一个可扩充、复用的组件是必不可少的,我带着学习的心态,通过查询了一些同志的案例,下面将实现心得分享一下。

实现步骤

1、template解构

<template>
  <div
    class="page-nav"
    style="-moz-user-select: none"
    onselectstart="return false;"
  >
    <span
      class="first nav-hover"
      @click="onFirst"
      :class="state.a ? 'disabled' : ''"
      >{{ state.first }}</span
    >
    <font-awesome-icon
      @click="onPrev"
      class="angle nav-hover"
      :class="state.b ? 'disabled' : ''"
      icon="angle-left"
    />
    <ul>
      <li
        v-for="(item, index) in state.list"
        @click="buttonPage(item)"
        :key="index"
        :class="{ active: state.currentPage == item }"
      >
        {{ item }}
      </li>
    </ul>
    <font-awesome-icon
      @click="onNext"
      class="angle nav-hover"
      :class="state.c ? 'disabled' : ''"
      icon="angle-right"
    />
    <span
      class="end nav-hover"
      @click="onLast"
      :class="state.d ? 'disabled' : ''"
      >{{ state.last }}</span
    >
    <input
      :value="state.value"
      type="text"
      placeholder="..."
      @input="pageChange"
    />
    <span class="nav-hover" @click="onJust">跳转</span>
  </div>
</template>

这里我标签使用的随意一些,还引入了fontAwesome的一些东西,实现思路借鉴了其他人的东西,通过:class来激活禁用控件。主要的逻辑在js上。
2、script

<script setup>
import { ref, defineProps, defineEmits, onMounted, reactive } from "vue";

const props = defineProps({
  config: Object,
});
const emit = defineEmits();
const state = reactive({
  first: "首页",
  last: "尾页",
  a: false,
  b: false,
  c: false,
  d: false,
  page: 1,
  pageSize: 10,
  total: 0, //总数
  list: [], //页数数组
  currentPage: 1, //当前页
  sumPages: 0, //算得页总数
  recordPage: 0, //初始页数,
  maxShowPage: 8, //item显示数
  step: 4, //步数
  value: 1,
  input: 0,
});
onMounted(() => {
  state.total = props.config.total;
  state.pageSize = props.config.pageSize;
  state.sumPages = Math.ceil(state.total / state.pageSize);
  // 父组件拿到总数
  emit("onCount", state.sumPages);
  if (state.sumPages == 1) {
    state.a = true;
    state.b = true;
    state.c = true;
    state.d = true;
  }
  // 初始化pageList
  state.sumPages >= state.maxShowPage
    ? (state.recordPage = state.maxShowPage)
    : (state.recordPage = state.sumPages);
  for (var i = 1; i <= state.recordPage; i++) {
    state.list.push(i);
  }
  state.value = state.currentPage;
  state.input = state.currentPage;
  if (state.currentPage == 1) {
    state.a = true;
    state.b = true;
    state.c = false;
    state.d = false;
  } else if (state.currentPage == state.sumPages) {
    state.a = false;
    state.b = false;
    state.c = true;
    state.d = true;
  } else {
    state.a = false;
    state.b = false;
    state.c = false;
    state.d = false;
  }
});
const countPages = (start, end) => {
  state.list = [];
  for (var i = start; i <= end; i++) {
    state.list.push(i);
  }
};
const pageChange = (val) => {
  state.input = parseInt(val.target.value);
};
const onJust = () => {
  if (state.input <= state.sumPages && state.input > 0 && state.input != NaN) {
    buttonPage(state.input);
  } else {
    state.value = "";
  }
};
const onFirst = () => {
  buttonPage(1);
};
const onPrev = () => {
  if (state.currentPage > 1) {
    buttonPage(state.currentPage - 1);
  }
};
const onNext = () => {
  if (state.currentPage < state.sumPages) {
    buttonPage(state.currentPage + 1);
  }
};
const onLast = () => {
  buttonPage(state.sumPages);
};

const buttonPage = (val) => {
  if (val == 1) {
    state.a = true;
    state.b = true;
    state.c = false;
    state.d = false;
    countPages(1, state.recordPage);
  } else if (val == state.sumPages) {
    state.a = false;
    state.b = false;
    state.c = true;
    state.d = true;
    // 限制最大页比最大显示数小的情况
    state.sumPages > state.maxShowPage
      ? countPages(state.sumPages - state.maxShowPage, state.sumPages)
      : countPages(1, state.sumPages);
  } else {
    if (val <= state.maxShowPage) {
      countPages(1, state.recordPage);
    } else if (val >= state.maxShowPage) {
      (val <= state.sumPages- state.step)?
      countPages(val-state.step, val+state.step):
      countPages(state.sumPages-state.maxShowPage, state.sumPages)
    }
    state.a = false;
    state.b = false;
    state.c = false;
    state.d = false;
  }
  state.value = val;
  state.currentPage = val;
  state.input = val;

  emit("onMyClick", val);
};
</script>

vue3已经高度的提供了函数式编程,可以看出来我们的代码具有高独立性,就是逻辑有些臃肿,因为我的vue水平也是在入门,我们写的是一个子组件,要靠父组件的传参来执行效果

<pageNavVue :config="state.pageConfig" @onCount="pageCount" @onMyClick="pageClick"></pageNavVue>

import { reactive } from "vue";
const state = reactive({
  pageConfig: {
    total: 15,
    pageSize: 7,
  },
  nowPage:'1',
  countPage:"x"
});
const pageClick=(val)=>{
  state.nowPage=val;
}
const pageCount=(val)=>{
  state.countPage=val;
}

这里还包含了一些子父组件交互的方法。
3、css-scss

<style scoped lang="scss">
.table {
  width: 100%;
  text-align: left;
  margin-top: 3rem;
  tr{

    th{
      color: cadetblue;
      padding: 1rem;
    }
    td{
      padding: 1rem;
      border-top: 1px solid rgba(0,0,0,.12);
      border-bottom: 1px solid rgba(0,0,0,.12);
      box-sizing: border-box;
      a{
        display: inline-block;
        padding: .5rem;
        color: rgb(248, 29, 29);
        border-radius: 3rem;
        margin-right: .5rem;
        cursor: pointer;
        font-size: 1.5rem;
        &:active{
          background-color: rgba($color: cadetblue, $alpha: .1);
        }
      }
    }
    .td-end{
      color: cadetblue;
      font-size: 1.5rem;
    }
  }
}
</style>

这是我第一次使用scss,我感受到了它带来的便捷,维护开发都变得easy

4、心得总结

实现难点无非就是js的逻辑控制,根据父组件传来的总条数和每页数量来求取页数。 配合vue的特性,我们使用几个关键的变量让工作执行起来,相信刚入门的同学和我一样,对于组件的理解不深刻,感想不敢做,敢做不会做,我的建议是向前看,只有不断的思考,磨练,吸收,我们才能具备一个开发人员的品质。

我想重点说下这几个参数,list数组是展示页数item的容器

list: [], //页数数组
currentPage: 1, //当前页
sumPages: 0, //算得页总数
recordPage: 0, //初始页数,
maxShowPage: 8, //item显示数
step: 4, //步数

在这里插入图片描述

currentPage,是当前选中页数,也是组件动态运行的关键
为什么要有recordPage,我的想法是简单直接的恢复list状态,当点击首页时
在这里插入图片描述
if (val == 1) {
state.a = true;
state.b = true;
state.c = false;
state.d = false;
countPages(1, state.recordPage); //直接还原了数组,
}
maxShowPage:如百度的分页组件可以发现,我们在左右点击时,item出现多个是体验友好的
在这里插入图片描述
直接多出4个,可以快速选择,我利用的思想就是通过计算重置list

const countPages = (start, end) => {
  state.list = [];
  for (var i = start; i <= end; i++) {
    state.list.push(i);
  }
};

关键的地方是怎么重置,如何界定数组

 else if (val == state.sumPages) {
    state.a = false;
    state.b = false;
    state.c = true;
    state.d = true;
    // 到尾页时,这里会有俩种情况,一个是总页数达不到maxShowPage,这个时候就是直接数组countPages(1, state.sumPages),如果是够maxShowPage,那么就是sumPages到它的前maxShowPage这几个数
    state.sumPages > state.maxShowPage
      ? countPages(state.sumPages - state.maxShowPage, state.sumPages)
      : countPages(1, state.sumPages);
  } else {
  // 不是尾页时,这里会有3种情况,一个是向左点击,<最大页,直接数组,countPages(1, state.recordPage),第二个是向右点击超出8,那么数组的限定就得改变countPages(val-state.step, val+state.step),第三种情况,数组的尾端只能限定在总页数减去步长的地方,否则数组就错误了。
    if (val <= state.maxShowPage) {
      countPages(1, state.recordPage);
    } else if (val >= state.maxShowPage) {
      (val <= state.sumPages- state.step)?
      countPages(val-state.step, val+state.step):
      countPages(state.sumPages-state.maxShowPage, state.sumPages)
    }
    state.a = false;
    state.b = false;
    state.c = false;
    state.d = false;
  }

这样写下来我也感觉不难,可是在做的时候确实苦思了一会儿,因为自己的整体能力还是有待提升的,记录在这里,谢谢阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Min;

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值