美文网首页
手写一个简易的vue分页器(三)

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

作者: 踏莎行 | 来源:发表于2021-06-10 11:25 被阅读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>
    

    相关文章

      网友评论

          本文标题:手写一个简易的vue分页器(三)

          本文链接:https://www.haomeiwen.com/subject/xnjeeltx.html