分頁元件在web專案中是十分常見的元件,讓我們使用Vue建立可重複使用的分頁元件,關於基本架構和相關事件監聽大家參考下本文
Web應用程式中資源分頁不僅對效能很有幫助,而且從使用者體驗的角度來說也是非常有用的。在這篇文章中,將了解如何使用Vue建立動態和可用的分頁元件。
基本結構
分頁元件應該允許使用者訪問第一個和最後一個頁面,向前和向後移動,並直接切換到近距離的頁面。
大多數應用程式在使用者每次變更頁面時都會發出API請求。我們需要確保元件允許這樣做,但是我們不希望在元件內發出這樣的請求。這樣,我們將確保元件在整個應用程式中是可重複使用的,並且請求都是在操作或服務層中進行的。我們可以透過使用使用者點擊的頁面的數字觸發事件來實現此目的。
有幾種可能的方法來實作API端點上的分頁。對於這個例子,我們假設API告訴我們每個頁面的結果數量、頁面總數和目前頁面。這些將會是我們的動態 props 。
相反,如果API只告訴記錄的總數,那麼我們可以透過將結果的數量除以每一頁的結果數來計算頁數: totalResults / resultsPerPage 。
我們想要渲染一個按鈕到第一頁、 上一頁、 頁面數量範圍、 下一頁和最後一頁:
[first] [next] [1] [2 ] [3] [previous] [last]
例如像下圖這樣的一個效果:
儘管我們希望渲染一個系列的頁面,但並不希望渲染所有可用頁面。讓我們允許在我們的元件中設定一個最多可見按鈕的 props 。
既然我們知道了我們想要的元件要做成什麼,需要哪些數據,我們就可以設定HTML結構和所需的 props 。
<template id="pagination"> <ul class="pagination"> <li> <button type="button">« First</button> </li> <li> <button type="button">«</button> </li> <!-- 页数的范围 --> <li> <button type="button">Next »</button> </li> <li> <button type="button">»</button> </li> </ul> </template> Vue.component('pagination', { template: '#pagination', props: { maxVisibleButtons: { type: Number, required: false, default: 3 }, totalPages: { type: Number, required: true }, total: { type: Number, required: true }, currentPage: { type: Number, required: true } } })
上面的程式碼註冊了一個pagination 元件,如果呼叫這個元件:
<p id="app"> <pagination></pagination> </p>
這時候看到的效果如下:
注意,為了能讓元件看起來好看一點,給組件添加了一點樣式。
事件監聽
現在我們需要通知父元件,當使用者點擊按鈕時,使用者點擊了哪個按鈕。
我們需要為每個按鈕新增一個事件監聽器。 v-on 指令 允許偵聽DOM事件。在本例中,我將使用 v-on 的快捷鍵 來偵聽單擊事件。
為了通知父節點,我們將使用 $emit 方法 來發出一個帶有頁面點擊的事件。
我們也要確保分頁按鈕只有在頁面可用時才唯一一個目前狀態。為了這樣做,將使用 v-bind 將 disabled 屬性的值與目前頁面綁定。我們還是使用 :v-bind 的快捷鍵 : 。
為了保持我們的 template 乾淨,將使用 computed 屬性 來檢查按鈕是否已停用。使用 computed 也會被緩存,這意味著只要 currentPage 不會更改,對相同計算屬性的幾個訪問將返回先前計算的結果,而不必再次運行該函數。
<template id="pagination"> <ul class="pagination"> <li> <button type="button" @click="onClickFirstPage" :disabled="isInFirstPage">« First</button> </li> <li> <button type="button" @click="onClickPreviousPage" :disabled="isInFirstPage">«</button> </li> <li v-for="page in pages"> <button type="button" @click="onClickPage(page.name)" :disabled="page.isDisabled"> {{ page.name }}</button> </li> <li> <button type="button" @click="onClickNextPage" :disabled="isInLastPage">Next »</button> </li> <li> <button type="button" @click="onClickLastPage" :disabled="isInLastPage">»</button> </li> </ul> </template> Vue.component('pagination', { template: '#pagination', props: { maxVisibleButtons: { type: Number, required: false, default: 3 }, totalPages: { type: Number, required: true }, total: { type: Number, required: true }, currentPage: { type: Number, required: true } }, computed: { isInFirstPage: function () { return this.currentPage === 1 }, isInLastPage: function () { return this.currentPage === this.totalPages } }, methods: { onClickFirstPage: function () { this.$emit('pagechanged', 1) }, onClickPreviousPage: function () { this.$emit('pagechanged', this.currentPage - 1) }, onClickPage: function (page) { this.$emit('pagechanged', page) }, onClickNextPage: function () { this.$emit('pagechanged', this.currentPage + 1) }, onClickLastPage: function () { this.$emit('pagechanged', this.totalPages) } } })
在呼叫pagination 元件時,將totalPages 和total 以及currentPage 傳到元件中:
<p id="app"> <pagination :total-pages="11" :total="120" :current-page="currentPage"></pagination> </p> let app = new Vue({ el: '#app', data () { return { currentPage: 2 } } })
執行上面的程式碼,將會報錯:
不難發現,在pagination元件中,咱們還少了pages 。從前面介紹的內容,我們不難發現,需要計算 pages 的值。
Vue.component('pagination', { template: '#pagination', props: { maxVisibleButtons: { type: Number, required: false, default: 3 }, totalPages: { type: Number, required: true }, total: { type: Number, required: true }, currentPage: { type: Number, required: true } }, computed: { isInFirstPage: function () { return this.currentPage === 1 }, isInLastPage: function () { return this.currentPage === this.totalPages }, startPage: function () { if (this.currentPage === 1) { return 1 } if (this.currentPage === this.totalPages) { return this.totalPages - this.maxVisibleButtons + 1 } return this.currentPage - 1 }, endPage: function () { return Math.min(this.startPage + this.maxVisibleButtons - 1, this.totalPages) }, pages: function () { const range = [] for (let i = this.startPage; i <= this.endPage; i+=1) { range.push({ name: i, isDisabled: i === this.currentPage }) } return range } }, methods: { onClickFirstPage: function () { this.$emit('pagechanged', 1) }, onClickPreviousPage: function () { this.$emit('pagechanged', this.currentPage - 1) }, onClickPage: function (page) { this.$emit('pagechanged', page) }, onClickNextPage: function () { this.$emit('pagechanged', this.currentPage + 1) }, onClickLastPage: function () { this.$emit('pagechanged', this.totalPages) } } })
這個時候得到的結果不再報錯,你在瀏覽器中會看到下圖這樣的效果:
新增樣式
現在我們的元件實作了原本想要的所有功能,而且添加了一些樣式,讓它看起來更像一個分頁元件,而不僅像是一個清單。
我們也希望使用者能夠清楚地辨識他們所在的頁面。讓我們改變表示目前頁面的按鈕的顏色。
為此,我們可以使用物件語法將HTML類別綁定到目前頁面按鈕。當使用物件語法綁定類別名稱時,Vue將在值變更時自動切換類別。
虽然 v-for 中的每个块都可以访问父作用域范围,但是我们将使用 method 来检查页面是否处于 active 状态,以便保持我们的 templage 干净。
Vue.component('pagination', { template: '#pagination', props: { maxVisibleButtons: { type: Number, required: false, default: 3 }, totalPages: { type: Number, required: true }, total: { type: Number, required: true }, currentPage: { type: Number, required: true } }, computed: { isInFirstPage: function () { return this.currentPage === 1 }, isInLastPage: function () { return this.currentPage === this.totalPages }, startPage: function () { if (this.currentPage === 1) { return 1 } if (this.currentPage === this.totalPages) { return this.totalPages - this.maxVisibleButtons + 1 } return this.currentPage - 1 }, endPage: function () { return Math.min(this.startPage + this.maxVisibleButtons - 1, this.totalPages) }, pages: function () { const range = [] for (let i = this.startPage; i <= this.endPage; i+=1) { range.push({ name: i, isDisabled: i === this.currentPage }) } return range } }, methods: { onClickFirstPage: function () { this.$emit('pagechanged', 1) }, onClickPreviousPage: function () { this.$emit('pagechanged', this.currentPage - 1) }, onClickPage: function (page) { this.$emit('pagechanged', page) }, onClickNextPage: function () { this.$emit('pagechanged', this.currentPage + 1) }, onClickLastPage: function () { this.$emit('pagechanged', this.totalPages) }, isPageActive: function (page) { return this.currentPage === page; } } })
接下来,在 pages 中添加当前状态:
<li v-for="page in pages"> <button type="button" @click="onClickPage(page.name)" :disabled="page.isDisabled" :class="{active: isPageActive(page.name)}"> {{ page.name }}</button> </li>
这个时候你看到效果如下:
但依然还存在一点点小问题,当你在点击别的按钮时, active 状态并不会随着切换:
继续添加代码改变其中的效果:
let app = new Vue({ el: '#app', data () { return { currentPage: 2 } }, methods: { onPageChange: function (page) { console.log(page) this.currentPage = page; } } })
在调用组件时:
<p id="app"> <pagination :total-pages="11" :total="120" :current-page="currentPage" @pagechanged="onPageChange"></pagination> </p>
这个时候的效果如下了:
到这里,基本上实现了咱想要的分页组件效果。
无障碍化处理
熟悉Bootstrap的同学都应该知道,Bootstrap中的组件都做了无障碍化的处理,就是在组件中添加了WAI-ARIA相关的设计。比如在分页按钮上添加 aria-label 相关属性:
在我们这个组件中,也相应的添加有关于WAI-ARIA相关的处理:
<template id="pagination"> <ul class="pagination" aria-label="Page navigation"> <li> <button type="button" @click="onClickFirstPage" :disabled="isInFirstPage" aria-label="Go to the first page">« First</button> </li> <li> <button type="button" @click="onClickPreviousPage" :disabled="isInFirstPage" aria-label="Previous">«</button> </li> <li v-for="page in pages"> <button type="button" @click="onClickPage(page.name)" :disabled="page.isDisabled" :aria-label="`Go to page number ${page.name}`"> {{ page.name }}</button> </li> <li> <button type="button" @click="onClickNextPage" :disabled="isInLastPage" aria-label="Next">Next »</button> </li> <li> <button type="button" @click="onClickLastPage" :disabled="isInLastPage" aria-label="Go to the last page">»</button> </li> </ul> </template>
这样有关于 aria 相关的属性就加上了:
最终的效果如下,可以点击下面的连接访问:
相关推荐:
以上是使用Vue建立可重複使用的分頁元件的詳細內容。更多資訊請關注PHP中文網其他相關文章!