手写一个简易的vue分页器(三)

2021-06-10  本文已影响0人  踏莎行

上一节

前面我们做完了分页器的基本功能,现在就做一下与父组件的交互

与父组件传递信息

当我们组件中的页码发生变化时可能需要通知父组件,比如父组件显示的第一页的数据,我们分页组件的myCurrentPage变成了2就是要获取第二页的数据,这时父组件就要重新获取数据。使用一个自定义事件,在上一节的setCurrentPage函授里面this.myCurrentPage = page;操作之后加上一个

this.$emit("currentChange", page);

用法就是上节里面的

<Pagination
  :currentPage="xxx"
  :total="xxx"
  :pageSize="xxx"
  :showPageNo="xxx"
  @currentChange="xxxxxx"
></Pagination>

父组件与分页组件传递信息

还有一种可能性,父组件的数据发生变化了,比如父组件通过props传递给子组件的currentPage,在初始化的时候才会拿到,后面再修改之后,data中的myCurrentPage: this.currentPage这条数据就不会发生更新,所以当父组件的这个值发生改变之后就要通知子组件。要做一个复用性较高的组件,我觉的不应该是让父组件主动发信息给组件,而是让子组件自己去监听这条数,所以在子组件中添加watch监听,父组件的变了,分页组件就能监听到,立刻更新data数据

 watch: {
    /**
     * 监视父组件传来的页码。同步更新页码
     */
    currentPage(value) {
      this.myCurrentPage = value;
    },
  },

优化

我们在做动态渲染按钮的时候,同时使用了v-if和v-for,编辑器可能会给你报错,不会影响程序的运行,但是这两者放在一起使用效率非常低

<button
  v-for="item in startEnd.end"
  v-if="item >= startEnd.start"
  :key="item"
  :class="{ active: item === myCurrentPage }"
>
  {{ item }}
</button> 

优化的方法很简单,在数据渲染之前先对数据进行筛选,在分页组件中再定义一个计算属性startEndArr,将start到end之间的数据筛选出来,在遍历的时候直接从start开始遍历,返回数组arr

computed: {
    startEnd() {
     //  .........
      return { start, end };
    },

    startEndArr(){
      const arr = []
      const {start, end} = this.startEnd
      for(let page = start; page <= end; page++){
        arr.push(page)
      }
      return arr
    }
  },

然后直接循环arr即可

<button
  v-for="item in startEndArr"
  :key="item"
  :class="{ active: item === myCurrentPage }"
  @click="setCurrentPage(item)"
>
  {{ item }}
</button>

完整的分页组件

<template>
  <div class="pageination">
    <!-- 当当前页是1的时候,禁用 -->
    <button
      :disabled="myCurrentPage === 1"
      :class="{ disabled: myCurrentPage === 1 }"
      @click="setCurrentPage(myCurrentPage - 1)"
    >
      上一页
    </button>
    <button v-if="startEnd.start > 1"  @click="setCurrentPage(1)">1</button>
    <button class="disabled" v-if="startEnd.start > 2">...</button>
    <button
      v-for="item in startEndArr"
      :key="item"
      :class="{ active: item === myCurrentPage }"
      @click="setCurrentPage(item)"
    >
      {{ item }}
    </button>
    <button class="disabled" v-if="startEnd.end < totalPage - 1">...</button>
    <button v-if="startEnd.end < totalPage" @click="setCurrentPage(totalPage)">
      {{ totalPage }}
    </button>
    <button
      :disabled="myCurrentPage === totalPage"
      :class="{ disabled: myCurrentPage === totalPage }"
      @click="setCurrentPage(myCurrentPage + 1)"
    >
      下一页
    </button>
    <button class="disabled">共 {{ total }} 条</button>
  </div>
</template>

<script>
export default {
  name: "Pageination",
  props: {
    currentPage: {
      type: Number,
      default: 1,
    },
    total: {
      type: Number,
      default: 0,
    },
    pageSize: {
      type: Number,
      default: 10,
    },

    showPageNo: {
      type: Number,
      default: 5,
      validator: function (value) {
        return value % 2 === 1;
      },
    },
  },

  data() {
    return {
      myCurrentPage: this.currentPage,
    };
  },

  computed: {
    totalPage() {
      const { total, pageSize } = this;
      return Math.ceil(total / pageSize);
    },

    startEnd() {
      const { myCurrentPage, showPageNo, totalPage } = this;
      let start, end;
      start = myCurrentPage - Math.floor(showPageNo / 2);
      if (start < 1) {
        start = 1;
      }

      end = start + showPageNo - 1;

      if (end > totalPage) {
        // 修改end为totalPage
        end = totalPage;
        // reset start
        start = end - showPageNo + 1;
        if (start < 1) {
          start = 1;
        }
      }
      return { start, end };
    },

    startEndArr(){
      const arr = []
      const {start, end} = this.startEnd
      for(let page = start; page <= end; page++){
        arr.push(page)
      }

      return arr
    }
  },

  methods: {
    // 切换页码
    setCurrentPage(page) {
      // 如果页码没有改变,依然点击了,直接return
      if (page === this.myCurrentPage) return;

      this.myCurrentPage = page;
      // 分发自定义事件,告诉父组件
      this.$emit("currentChange", page);
    },
  },

  watch: {
    /**
     * 监视父组件传来的页码。同步更新页码
     */
    currentPage(value) {
      this.myCurrentPage = value;
    },
  },
};
</script>

<style lang="less" scoped>
.pageination {
  button {
    margin: 0 5px;
    background-color: #f4f4f5;
    color: #606266;
    outline: none;
    border-radius: 2px;
    pad: 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;

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

    &.disabled {
      cursor: not-allowed;
      color: #ccc;
    }
  }
}
</style>
上一篇下一篇

猜你喜欢

热点阅读