VUE实现一个分页组件

时间:2022-12-20 08:56:31

分页是WEB开发中很常用的功能,尤其是在各种前后端分离的今天,后端API返回数据,前端根据数据的count以及当前页码pageIndex来计算分页页码并渲染到页面上已经是一个很普通很常见的功能了。从最开始的jquery时代到现在的各种各样的前端框架时代,分页功能都是必不可少的。
分页大多数(基本上)情况下都是对异步数据列表的处理,这里首先需要明白一下分页的流程。
在已知每页显示数据量pageSize以及当前页码pageIndex的情况下:

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

由于获取数据条件的变化(假设是个搜索,关键词变了),count是不定的;再或者,有个select下拉框,来控制每页显示的数据量pageSize,当它变化的时候,总页码肯定也是要变化的。因此很多情况下要重新计算页码并渲染。

了解了流程,在Vue中实现一个分页组件也就变得简单了。

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

由于获取数据条件的变化(假设是个搜索,关键词变了),count是不定的;再或者,有个select下拉框,来控制每页显示的数据量pageSize,当它变化的时候,总页码肯定也是要变化的。因此很多情况下要重新计算页码并渲染。

了解了流程,在Vue中实现一个分页组件也就变得简单了。

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

分页组件

template

< template >
     < ul class = "mo-paging" >
         <!-- prev -->
         < li :class = "['paging-item', 'paging-item--prev', {'paging-item--disabled' : index === 1}]" @ click = "prev" >prev</ li >
 
         <!-- first -->
         < li :class = "['paging-item', 'paging-item--first', {'paging-item--disabled' : index === 1}]" @ click = "first" >first</ li >
 
         < li :class = "['paging-item', 'paging-item--more']" v-if = "showPrevMore" >...</ li >
 
         < li :class = "['paging-item', {'paging-item--current' : index === pager}]" v-for = "pager in pagers" @ click = "go(pager)" >{{ pager }}</ li >
 
         < li :class = "['paging-item', 'paging-item--more']" v-if = "showNextMore" >...</ li >
 
         <!-- last -->
         < li :class = "['paging-item', 'paging-item--last', {'paging-item--disabled' : index === pages}]" @ click = "last" >last</ li >
 
         <!-- next -->
         < li :class = "['paging-item', 'paging-item--next', {'paging-item--disabled' : index === pages}]" @ click = "next" >next</ li >
     </ ul >
</ template >

style(scss)

.mo-paging {
     display : inline- block ;
     padding : 0 ;
     margin : 1 rem 0 ;
     font-size : 0 ;
     list-style : none ;
     user-select: none ;
     > .paging-item {
         display : inline ;
         font-size : 14px ;
         position : relative ;
         padding : 6px 12px ;
         line-height : 1.42857143 ;
         text-decoration : none ;
         border : 1px solid #ccc ;
         background-color : #fff ;
         margin-left : -1px ;
         cursor : pointer ;
         color : #0275d8 ;
         &:first-child {
             margin-left : 0 ;
         }
         &:hover {
             background-color : #f0f0f0 ;
             color : #0275d8 ;
         }
         &.paging-item--disabled,
         &.paging-item--more{
             background-color : #fff ;
             color : #505050 ;
         }
         //禁用
         &.paging-item--disabled {
             cursor : not-allowed;
             opacity: . 75 ;
         }
         &.paging-item--more,
         &.paging-item--current {
             cursor : default ;
         }
         //选中
         &.paging-item--current {
             background-color : #0275d8 ;
             color : #fff ;
             position : relative ;
             z-index : 1 ;
             border-color : #0275d8 ;
         }
     }
}

javascript

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)
             }
         }
     },
     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
         }
     },
     data () {
         return {
             index : this .pageIndex, //当前页码
             limit : this .pageSize, //每页显示条数
             size : this .total || 1, //总记录数
             showPrevMore : false ,
             showNextMore : false
         }
     },
     watch : {
         pageIndex(val) {
             this .index = val || 1
         },
         pageSize(val) {
             this .limit = val || 10
         },
         total(val) {
             this .size = val || 1
         }
     }
}

父组件中使用

< template >
     < div class = "list" >
         < template v-if = "count" >
             < ul >
                 < li v-for = "item in items" >...</ li >
             </ ul >
             < mo-paging :page-index = "currentPage" :totla = "count" :page-size = "pageSize" @ change = "pageChange" >
             </ mo-paging >
         </ template >
     </ div >
</ template >
< script >
     import MoPaging from './paging'
     export default {
         //显示的声明组件
         components : {
             MoPaging
         },
         data () {
             return {
                 pageSize : 20 , //每页显示20条数据
                 currentPage : 1, //当前页码
                 count : 0, //总记录数
                 items : []
             }
         },
         methods : {
             //获取数据
             getList () {
                 //模拟
                 let url = `/api/list/?pageSize=${this.pageSize}¤tPage=${this.currentPage}`
                 this.$http.get(url)
                 .then(({body}) => {
 
                     //子组件监听到count变化会自动更新DOM
                     this.count = body.count
                     this.items = body.list
                 })
             },
 
             //从page组件传递过来的当前page
             pageChange (page) {
                 this.currentPage = page
                 this.getList()
             }
         },
         mounted() {
             //请求第一页数据
             this.getList()
         }
     }
</ script >

本文标题:Vue实现一个分页组件
本文链接:https://smohan.net/blog/pgk1qr
本站使用「 署名 4.0 国际」创作共享协议,转载或使用请署名并注明出处。 相关说明 »