Vue2自定义分页组件

分页是WEB开发中很常用的功能,尤其是在各种前后端分离的今天,后端API返回数据,前端根据数据的count以及当前页码pageIndex来计算分页页码并渲染到页面上已经是一个很普通很常见的功能了。博主之前的公司分页是用的一个jquery插件,使用起来真的是诸多不便。今天我们自己手写一个vue2的分页组件,供以后开发使用。

  • 请求API,返回第一屏数据(pageSize内)以及所有相关条件的数据总量count。
  • 将数据总量传递给page组件,来计算页码并渲染到页面上。
  • 点击页码,发送请求获取该页码的数据,返回数据总量count以及该页码下的数据条目。

简单处理,样式类似于bootstrap的分页组件,在第一页时,禁用上一页,以及首页按钮;在最后一页时,禁用下一页,以及尾页按钮;超出范围的页码以...来代替,效果图如下:


好吧,下面晒出我的分页组件模版:


模版写粗来了,是不是很一目了然的感觉,css就不在这里摆出来了。
好了,接下来就是比较复杂的js代码了,我们先思考一下,这个组件肯定是作为子组件被引用到一个父组件里面。

export default {
    name : 'MoPaging',
    //通过props来接受从父组件传递过来的值
    props : {
        //页面中的可见页码,其他的以...替代, 必须是奇数
        perPages : { 
            type : Number,
            default : 5 
        },

        //当前页码
        pageIndex : {
            type : Number,
            default : 1
        },

        //每页显示条数
        pageSize : {
            type : Number,
            default : 10
        },

        //总记录数
        total : {
            type : Number,
            default : 1
        }
 },

   methods : {
        prev(){
            if (this.index > 1) {
                this.go(this.index - 1)
            }
        },
        next(){
            if (this.index < this.pages) {
                this.go(this.index + 1)
            }
        },
        first(){
            if (this.index !== 1) {
                this.go(1)
            }
        },
        last(){
            if (this.index != this.pages) {
                this.go(this.pages)
            }
        },
        go (page) {
            if (this.index !== page) {  //点击的页码不是当前页码
                this.index = page
                //父组件通过change方法来接受当前的页码
                this.$emit('change', this.index)
            }
        }
    }

其实这些method里面的prev,next都还比较简单,如果对父子组件通信不了解的同学,文章结尾我会给一个例子,关键字$emit。

data () {
        return {
            index : this.pageIndex, //当前页码
            limit : this.pageSize, //每页显示条数
            size : this.total || 1, //总记录数
            showPrevMore : false,   //前后有2个 ... 根据这里判断是否显示
            showNextMore : false
        }
    },
computed : {

        //计算总页码
        pages(){
            return Math.ceil(this.size / this.limit)
        },

        //计算页码,当count等变化时自动计算
        pagers () {
            const array = []
            const perPages = this.perPages
            const pageCount = this.pages
            let current = this.index
            const _offset = (perPages - 1) / 2


            const offset = {
                start : current - _offset,
                end   : current + _offset
            }

            //-1, 3
            if (offset.start < 1) {
                offset.end = offset.end + (1 - offset.start)
                offset.start = 1
            }
            if (offset.end > pageCount) {
                offset.start = offset.start - (offset.end - pageCount)
                offset.end = pageCount
            }
            if (offset.start < 1) offset.start = 1

            this.showPrevMore = (offset.start > 1)
            this.showNextMore = (offset.end < pageCount)

            for (let i = offset.start; i <= offset.end; i++) {
                array.push(i)
            }

            return array
        }

        watch : {
            pageIndex(val) {
                this.index = val || 1
        },
            pageSize(val) {
                this.limit = val || 10
        },
            total(val) {
               this.size = val || 1
        }
    }
    }

大家可能看到pagers里面的代码被吓到了,其实也没什么,里面只是做了一些判断,提供左右2边的... 是否现实的依据。我们来分析一下:

  1. 中间显示的条目是5,左边的 ... 在当前页面大于3时显示,这个很好判断。
  2. 中间显示的条目是5,右边的 ... 在当前页面小于18时显示,这个很好判断。
  3. 当前页码index在pagers数组的中间,这是一个奇数个的数组。

其实到了这里也差不多了,我们来看一下父组件的写法:


这个父组件向下传递了一些数据给分页组件,如total,page-index,page-size。


mounted当页面挂载时,就去获取数据。当在分页组件点击了某个页数后,会触发父组件的pageChange事件,这个函数里面的page是通过emit传递过来的。

好了,最后讲一下父子组件通信的问题吧。。。
父组件:

{{ total }}

new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal() { this.total += 1 } } })

子组件:

Vue.component('button-counter', {
  template: '',
  data: function () {
    return {
      counter: 0
    }
  },
  methods: {
    increment() {
      this.counter += 1
      this.$emit('increment')
    }
  },
})

上面讲的两种方法都父子组件之间的通信,有时候非父子关系的组件也需要通信。在 Vue1.0 时代,可以通过 $dispatch 和 $broadcast 来解决,首先 dispatch 到根组件,然后再 broadcast 到子组件。Vue2.0 中官方推荐用 event bus 或者 vuex 解决,event bus 的本质是一个发布者订阅者模式。

var bus = new Vue() Vue.component('Increment', { template: ``, data: function() { return {count: 0} }, methods: { increment: function(){ var increment = this.count++ bus.$emit('inc', increment) } } }) Vue.component('Display', { template: `

Clicked: {{count}} times

`, data: function(){ return {count: 0} }, created: function(){ bus.$on('inc', function(num){ this.count = num }.bind(this)) } }) new Vue({ el: "#example", })

相信大家一看就会懂,这个时候同级组件的沟通需要经过父组件bus,然而在做项目的时候我们有vuex,就不需要这个了。。。

你可能感兴趣的:(Vue2自定义分页组件)