如何通過vue實現一款簡單通用的翻頁組件
預覽
先上一波效果圖:
基本元素
首先,翻頁組件(以下稱“pager組件”)一般擁有的元素有:
- 上一頁
- ***頁
- 中間顯示的頁碼
- ***一頁
- 下一頁
初始化時需要的配置有:
- totalPage(總頁數)
- initPage(初始頁)
- showPrev(是否顯示上一頁)
- showNext(是否顯示下一頁)
- showItems(中間顯示幾頁)
- showJump(是否顯示跳轉到第幾頁)
這些可以通過vue的props來接收。
另外,pager組件本身需要有一個記錄當前頁的currentPage,pages數組用來容納中間顯示的頁碼,jumpPage綁定輸入的跳轉頁碼。
基本實現
對應的代碼為:
- <template>
- <div class="pager-wrapper" v-if="totalPage > 0">
- <div class="pager-pages">
- <a v-show="currentPage > 1 && showPrev" @click="go(currentPage - 1)">上一頁</a>
- <a :class="{active: currentPage == 1 ? true : false}" @click="go(1)">1</a>
- <strong v-show="pages[0] > 2">...</strong>
- <a v-for="page in pages" :class="{active: currentPage == page ? true : false}" @click="go(page)">{{page}}</a>
- <strong v-show="pages[pages.length-1] < totalPage - 1">...</strong>
- <a v-if="totalPage > 1" :class="{active: currentPage == totalPage ? true : false}" @click="go(totalPage)">{{totalPage}}</a>
- <a v-show="currentPage < totalPage && showNext" @click="go(currentPage + 1)">下一頁</a>
- </div>
- <div v-if="showJump" v-show="totalPage > 1" class="pager-jump">
- <span>共<em class="jump-total">{{totalPage}}</em>頁 ,跳至</span>
- <input type="number" min="1" :max="totalPage" v-model="jumpPage" class="jump-input">
- <span>頁</span>
- <a @click="go(jumpPage)">確定</a>
- </div>
- </div>
- </template>
- <script>
- export default {
- props: {
- totalPage: { // 總頁數
- type: Number,
- default: 1,
- required: true
- },
- showItems: { // 顯示出來的頁數,如: 1 ... 34[5]67 ... 10
- type: Number,
- default: 5
- },
- showPrev: { // 是否顯示“上一頁”
- type: Boolean,
- default: true
- },
- showNext: { // 是否顯示“下一頁”
- type: Boolean,
- default: true
- },
- showJump: { // 是否顯示“跳轉”
- type: Boolean,
- default: true
- },
- initPage: {
- type: Number,
- default: 1
- }
- },
- data () {
- return {
- currentPage: 0,
- pages: [],
- jumpPage: 0,
- }
- },
- created () {// 初始化時currentPage賦值
- this.currentPage = this.initPage
- }
- methods: {
- go (page) {
- if(page < 1) {
- page = 1
- }
- if(page > this.totalPage) {
- page = this.totalPage
- }
- if(page === this.currentPage) {
- return
- }
- this.currentPage = parseInt(page,10)
- this.$emit('go-page',{
- page: this.currentPage
- })
- }
- },
- watch: {
- currentPage (newVal) {
- this.jumpPage = newVal
- },
- initPage (newVal) {
- if(this.currentPage !== newVal) {
- this.currentPage = newVal
- }
- }
- }
- }
- </script>
接下來就是pages數組的值如何獲取到。由于pages始終是跟當前頁currentPage以及配置中需要顯示的showItems強相關的,那么完全可以將pages改為計算屬性:
- computed: {
- pages () {
- // 根據起始頁碼和結束頁碼得到頁碼數組
- let getPages = (start,end) => {
- if(start <= 1 || start > end || start >= this.totalPage) {
- start = 2
- }
- if(end >= this.totalPage || end < start || end <= 1) {
- end = this.totalPage - 1
- }
- let arr = []
- for(let i = start; i <= end; i++) {
- arr.push(i)
- }
- return arr
- }
- let counts = this.showItems
- if(this.totalPage < counts + 2) {
- return getPages(2,this.totalPage)
- } else {
- if(this.currentPage <= Math.ceil(counts/2)) {
- return getPages(2,counts)
- } else if(this.currentPage >= this.totalPage - Math.floor(counts/2)) {
- return getPages(this.totalPage + 1 - counts,this.totalPage - 1)
- } else {
- let half = Math.ceil(counts/2) - 1
- let end = this.currentPage + half
- if(counts % 2 === 0) {
- end++
- }
- return getPages(this.currentPage - half,end)
- }
- }
- }
- }
功能拓展
到這里一個普通的翻頁組件基本上就實現了(樣式自己可以去定制)。但是很多時候(特別是一些管理后臺),結合vue-router做成SPA,通常會有這樣的需求:
翻到某個列表的某一頁之后,點擊某一項到編輯頁,編輯完成后希望能夠返回到跳轉之前的那一頁。
這個需求如果僅僅用上面的pager組件,實現起來就不是很方便。也許有人會說結合vuex可以,但是這樣的話需要在state中記錄下跳轉前的頁碼。假如有很多個翻頁列表,就需要記錄多個,這顯然并不優雅。
不過因為vue-router實現的優雅,我們要滿足上面的需求也很簡單:
首先props上增加mode配置,由于當mode為params時,跳轉需要知道是在哪一個路由下,所以:
- mode: {
- type: String,
- default: 'event' // 'event' | 'query' | 'params'
- },
- routeName: {
- type: String
- }
然后再在實際跳轉的邏輯方法go(page)里面,做點更改:
- go (page) {
- if(page < 1) {
- page = 1
- }
- if(page > this.totalPage) {
- page = this.totalPage
- }
- if(page === this.currentPage) {
- return
- }
- this.currentPage = parseInt(page,10)
- if(this.mode == 'query') {
- let query = this.$route.query
- query.page = this.currentPage
- this.$router.go({query: query})
- } else if(this.mode == 'params') {
- let params = this.$route.params
- params.page = this.currentPage
- this.$router.go({name: this.routeName,params: params})
- } else {
- this.$emit('go-page',{
- page: this.currentPage
- })
- }
- }
這樣基本上就完成了一個簡單且通用的翻頁組件啦,接下里就是發不到倉庫里供大家使用了。
本文最終實現的翻頁組件已經發布,大家可以看一波源碼:
總結
總體上講的比較淺顯,希望能有幫助。