Die Idee hinter den meisten Webanwendungen ist es, Daten aus der Datenbank abzurufen und sie dem Benutzer bestmöglich zu präsentieren. Wenn wir mit Daten arbeiten, gibt es Fälle, in denen die bestmögliche Präsentation die Erstellung einer Liste bedeutet.
Abhängig von der Datenmenge und ihrem Inhalt können wir entscheiden, ob wir alle Inhalte auf einmal anzeigen (sehr selten) oder nur einen bestimmten Teil eines größeren Datensatzes anzeigen (wahrscheinlicher). Der Hauptgrund für die Anzeige nur eines Teils der vorhandenen Daten ist, dass wir unsere Anwendungen so performant wie möglich halten und das Laden oder Anzeigen unnötiger Daten vermeiden wollen.
Wenn wir uns entscheiden, unsere Daten in „Häppchen“ anzuzeigen, benötigen wir eine Möglichkeit, durch diese Sammlung zu navigieren. Die zwei gängigsten Navigationsmethoden durch eine Datensammlung sind
Die erste ist die Paginierung, eine Technik, die die Datensammlung in eine bestimmte Anzahl von Seiten aufteilt, wodurch Benutzer von der Menge der Daten auf einer Seite nicht überfordert werden und sie jeweils einen Satz von Ergebnissen anzeigen können. Nehmen Sie diesen Blog, den Sie gerade lesen, als Beispiel. Die Homepage listet die neuesten 10 Beiträge auf. Um die nächste Gruppe von neuesten Beiträgen anzuzeigen, müssen Sie auf eine Schaltfläche klicken.

Die zweite gängige Technik ist das unendliche Scrollen, etwas, mit dem Sie wahrscheinlich vertraut sind, wenn Sie jemals eine Timeline auf Facebook oder Twitter durchgescrollt haben.

In diesem Beitrag werden wir uns eingehender mit dem ersten Typ befassen. Paginierung begegnet uns fast täglich, dennoch ist sie nicht gerade trivial zu erstellen. Es ist ein großartiger Anwendungsfall für eine Komponente, und genau das werden wir tun. Wir werden den Prozess der Erstellung einer Komponente durchlaufen, die für die Anzeige dieser Liste zuständig ist und die Aktion auslöst, die zusätzliche Artikel abruft, wenn wir auf eine bestimmte anzuzeigende Seite klicken. Mit anderen Worten, wir erstellen eine Paginierungskomponente in Vue.js, wie diese hier.
Lassen Sie uns die Schritte gemeinsam durchgehen.
Schritt 1: Erstellen Sie die ArticlesList-Komponente in Vue
Beginnen wir mit der Erstellung einer Komponente, die eine Liste von Artikeln anzeigt (aber noch ohne Paginierung). Wir nennen sie ArticlesList. In der Komponentenvorlage iterieren wir durch die Artikelsammlung und übergeben jedes einzelne Artikel-Element an eine ArticleItem-Komponente.
// ArticlesList.vue
<template>
<div>
<ArticleItem
v-for="article in articles"
:key="article.publishedAt"
:article="article"
/>
</div>
</template>
Im Skriptteil der Komponente legen wir die anfänglichen Daten fest
articles: Dies ist ein leeres Array, das mit Daten gefüllt wird, die immounted-Hook von der API abgerufen werden.currentPage: Dies wird zur Bearbeitung der Paginierung verwendet.pageCount: Dies ist die Gesamtzahl der Seiten, die immounted-Hook basierend auf der API-Antwort berechnet wird.visibleItemsPerPageCount: Dies ist die Anzahl der Artikel, die wir auf einer einzelnen Seite sehen möchten.
Zu diesem Zeitpunkt rufen wir nur die erste Seite der Artikelliste ab. Dies gibt uns eine Liste von zwei Artikeln.
// ArticlesList.vue
import ArticleItem from "./ArticleItem"
import axios from "axios"
export default {
name: "ArticlesList",
static: {
visibleItemsPerPageCount: 2
},
data() {
return {
articles: [],
currentPage: 1,
pageCount: 0
}
},
components: {
ArticleItem,
},
async mounted() {
try {
const { data } = await axios.get(
`?country=us&page=1&pageSize=${
this.$options.static.visibleItemsPerPageCount
}&category=business&apiKey=065703927c66462286554ada16a686a1`
)
this.articles = data.articles
this.pageCount = Math.ceil(
data.totalResults / this.$options.static.visibleItemsPerPageCount
)
} catch (error) {
throw error
}
}
}
Schritt 2: Erstellen Sie die Methode pageChangeHandle
Nun müssen wir eine Methode erstellen, die die nächste Seite, die vorherige Seite oder eine ausgewählte Seite lädt.
In der Methode pageChangeHandle ändern wir, bevor wir neue Artikel laden, den Wert von currentPage basierend auf einer an die Methode übergebenen Eigenschaft und rufen die Daten für eine bestimmte Seite von der API ab. Nach Erhalt neuer Daten ersetzen wir das vorhandene articles-Array durch die frischen Daten, die eine neue Seite mit Artikeln enthalten.
// ArticlesList.vue
...
export default {
...
methods: {
async pageChangeHandle(value) {
switch (value) {
case 'next':
this.currentPage += 1
break
case 'previous':
this.currentPage -= 1
break
default:
this.currentPage = value
}
const { data } = await axios.get(
`?country=us&page=${this.currentPage}&pageSize=${
this.$options.static.visibleItemsPerPageCount
}&category=business&apiKey=065703927c66462286554ada16a686a1`
)
this.articles = data.articles
}
}
}
Schritt 3: Erstellen Sie eine Komponente, um Seitenwechsel auszulösen
Wir haben die Methode pageChangeHandle, aber wir rufen sie nirgends auf. Wir müssen eine Komponente erstellen, die dafür zuständig ist.
Diese Komponente sollte folgende Dinge tun:
- Dem Benutzer erlauben, zur nächsten/vorherigen Seite zu wechseln.
- Dem Benutzer erlauben, zu einer bestimmten Seite innerhalb eines Bereichs von der aktuell ausgewählten Seite zu wechseln.
- Den Seitenbereich basierend auf der aktuellen Seite ändern.
Wenn wir das skizzieren würden, sähe es ungefähr so aus

Lassen Sie uns fortfahren!
Anforderung 1: Dem Benutzer erlauben, zur nächsten oder vorherigen Seite zu wechseln

Unsere BasePagination wird zwei Schaltflächen enthalten, die für den Wechsel zur nächsten und vorherigen Seite zuständig sind.
// BasePagination.vue
<template>
<div class="base-pagination">
<BaseButton
:disabled="isPreviousButtonDisabled"
@click.native="previousPage"
>
←
</BaseButton>
<BaseButton
:disabled="isNextButtonDisabled"
@click.native="nextPage"
>
→
</BaseButton>
</div>
</template>
Die Komponente akzeptiert die Eigenschaften currentPage und pageCount vom übergeordneten Element und gibt beim Klicken auf die nächste oder vorherige Schaltfläche entsprechende Aktionen an das übergeordnete Element zurück. Sie ist außerdem dafür verantwortlich, Schaltflächen zu deaktivieren, wenn wir uns auf der ersten oder letzten Seite befinden, um ein Überschreiten des bestehenden Bereichs zu verhindern.
// BasePagination.vue
import BaseButton from "./BaseButton.vue";
export default {
components: {
BaseButton
},
props: {
currentPage: {
type: Number,
required: true
},
pageCount: {
type: Number,
required: true
}
},
computed: {
isPreviousButtonDisabled() {
return this.currentPage === 1
},
isNextButtonDisabled() {
return this.currentPage === this.pageCount
}
},
methods: {
nextPage() {
this.$emit('nextPage')
},
previousPage() {
this.$emit('previousPage')
}
}
Wir werden diese Komponente direkt unter unseren ArticleItems in der ArticlesList-Komponente rendern.
// ArticlesList.vue
<template>
<div>
<ArticleItem
v-for="article in articles"
:key="article.publishedAt"
:article="article"
/>
<BasePagination
:current-page="currentPage"
:page-count="pageCount"
class="articles-list__pagination"
@nextPage="pageChangeHandle('next')"
@previousPage="pageChangeHandle('previous')"
/>
</div>
</template>
Das war der einfache Teil. Jetzt müssen wir eine Liste von Seitenzahlen erstellen, die es uns jeweils ermöglicht, eine bestimmte Seite auszuwählen. Die Anzahl der Seiten sollte anpassbar sein, und wir müssen auch sicherstellen, dass keine Seiten angezeigt werden, die uns über den Bereich hinausführen.
Anforderung 2: Dem Benutzer erlauben, zu einer bestimmten Seite innerhalb eines Bereichs zu wechseln

Beginnen wir mit der Erstellung einer Komponente, die als einzelne Seitenzahl verwendet wird. Ich nenne sie BasePaginationTrigger. Sie wird zwei Dinge tun: die von der BasePagination-Komponente übergebene Seitenzahl anzeigen und ein Ereignis auslösen, wenn der Benutzer auf eine bestimmte Zahl klickt.
// BasePaginationTrigger.vue
<template>
<span class="base-pagination-trigger" @click="onClick">
{{ pageNumber }}
</span>
</template>
<script>
export default {
props: {
pageNumber: {
type: Number,
required: true
}
},
methods: {
onClick() {
this.$emit("loadPage", this.pageNumber)
}
}
}
</script>
Diese Komponente wird dann in der BasePagination-Komponente zwischen den Schaltflächen „Weiter“ und „Zurück“ gerendert.
// BasePagination.vue
<template>
<div class="base-pagination">
<BaseButton />
...
<BasePaginationTrigger
class="base-pagination__description"
:pageNumber="currentPage"
@loadPage="onLoadPage"
/>
...
<BaseButton />
</div>
</template>
Im Skriptteil müssen wir eine weitere Methode hinzufügen (onLoadPage), die ausgelöst wird, wenn das Ereignis loadPage von der Trigger-Komponente ausgelöst wird. Diese Methode empfängt die angeklickte Seitenzahl und löst das Ereignis an die ArticlesList-Komponente weiter.
// BasePagination.vue
export default {
...
methods: {
...
onLoadPage(value) {
this.$emit("loadPage", value)
}
}
}
Dann hören wir in ArticlesList auf dieses Ereignis und lösen die Methode pageChangeHandle aus, die die Daten für unsere neue Seite abruft.
// ArticlesList
<template>
...
<BasePagination
:current-page="currentPage"
:page-count="pageCount"
class="articles-list__pagination"
@nextPage="pageChangeHandle('next')"
@previousPage="pageChangeHandle('previous')"
@loadPage="pageChangeHandle"
/>
...
</template>
Anforderung 3: Ändern Sie den Bereich der Seitenzahlen basierend auf der aktuellen Seite

OK, jetzt haben wir einen einzelnen Trigger, der uns die aktuelle Seite anzeigt und uns erlaubt, dieselbe Seite erneut abzurufen. Ziemlich nutzlos, finden Sie nicht? Lassen Sie uns diesen neu erstellten Trigger-Komponente nutzen. Wir benötigen eine Liste von Seiten, die es uns ermöglicht, von einer Seite zur nächsten zu springen, ohne die dazwischen liegenden Seiten durchlaufen zu müssen.
Wir müssen auch sicherstellen, dass die Seiten schön dargestellt werden. Wir wollen immer die erste Seite (ganz links) und die letzte Seite (ganz rechts) in der Paginierungsliste anzeigen und dann die verbleibenden Seiten dazwischen.
Wir haben drei mögliche Szenarien:
- Die ausgewählte Seitenzahl ist kleiner als die Hälfte der Listenbreite (z. B. 1 – 2 – 3 – 4 – 18)
- Die ausgewählte Seitenzahl ist größer als die Hälfte der Listenbreite, gezählt vom Ende der Liste (z. B. 1 – 15 – 16 – 17 – 18)
- Alle anderen Fälle (z. B. 1 – 4 – 5 – 6 – 18)
Um diese Fälle zu behandeln, erstellen wir eine berechnete Eigenschaft, die ein Array von Zahlen zurückgibt, die zwischen den Schaltflächen „Weiter“ und „Zurück“ angezeigt werden sollen. Um die Komponente wiederverwendbarer zu machen, akzeptieren wir eine Eigenschaft visiblePagesCount, die festlegt, wie viele Seiten in der Paginierungskomponente sichtbar sein sollen.
Bevor wir die Fälle einzeln durchgehen, erstellen wir einige Variablen
visiblePagesThreshold: Gibt an, wie viele Seiten von der Mitte (ausgewählte Seite) angezeigt werden sollen.paginationTriggersArray: Array, das mit Seitenzahlen gefüllt wird.visiblePagesCount: Erstellt ein Array mit der erforderlichen Länge.
// BasePagination.vue
export default {
props: {
visiblePagesCount: {
type: Number,
default: 5
}
}
...
computed: {
...
paginationTriggers() {
const currentPage = this.currentPage
const pageCount = this.pageCount
const visiblePagesCount = this.visiblePagesCount
const visiblePagesThreshold = (visiblePagesCount - 1) / 2
const pagintationTriggersArray = Array(this.visiblePagesCount - 1).fill(0)
}
...
}
...
}
Nun gehen wir jedes Szenario durch.
Szenario 1: Die ausgewählte Seitenzahl ist kleiner als die Hälfte der Listenbreite
Wir setzen das erste Element auf immer gleich 1. Dann iterieren wir durch die Liste und fügen jedem Element einen Index hinzu. Am Ende fügen wir den letzten Wert hinzu und setzen ihn gleich der letzten Seitenzahl – wir wollen bei Bedarf direkt zur letzten Seite springen können.
if (currentPage <= visiblePagesThreshold + 1) {
pagintationTriggersArray[0] = 1
const pagintationTriggers = pagintationTriggersArray.map(
(paginationTrigger, index) => {
return pagintationTriggersArray[0] + index
}
)
pagintationTriggers.push(pageCount)
return pagintationTriggers
}
Szenario 2: Die ausgewählte Seitenzahl ist größer als die Hälfte der Listenbreite, gezählt vom Ende der Liste
Ähnlich wie im vorherigen Szenario beginnen wir mit der letzten Seite und iterieren durch die Liste, diesmal subtrahieren wir den Index von jedem Element. Dann kehren wir das Array um, um die richtige Reihenfolge zu erhalten, und fügen 1 an erster Stelle in unser Array ein.
if (currentPage >= pageCount - visiblePagesThreshold + 1) {
const pagintationTriggers = pagintationTriggersArray.map(
(paginationTrigger, index) => {
return pageCount - index
}
)
pagintationTriggers.reverse().unshift(1)
return pagintationTriggers
}
Szenario 3: Alle anderen Fälle
Wir wissen, welche Zahl in der Mitte unserer Liste stehen soll: die aktuelle Seite. Wir wissen auch, wie lang die Liste sein soll. Das erlaubt uns, die erste Zahl in unserem Array zu ermitteln. Dann füllen wir die Liste, indem wir jedem Element einen Index hinzufügen. Am Ende fügen wir 1 an erster Stelle in unser Array ein und ersetzen die letzte Zahl durch unsere letzte Seitenzahl.
pagintationTriggersArray[0] = currentPage - visiblePagesThreshold + 1
const pagintationTriggers = pagintationTriggersArray.map(
(paginationTrigger, index) => {
return pagintationTriggersArray[0] + index
}
)
pagintationTriggers.unshift(1);
pagintationTriggers[pagintationTriggers.length - 1] = pageCount
return pagintationTriggers
Das deckt alle unsere Szenarien ab! Wir haben nur noch einen Schritt vor uns.
Schritt 5: Rendern Sie die Liste der Zahlen in der BasePagination-Komponente
Nachdem wir nun genau wissen, welche Zahl wir in unserer Paginierung anzeigen möchten, müssen wir für jede davon eine Trigger-Komponente rendern.
Das machen wir mit einer v-for-Direktive. Fügen wir auch eine bedingte Klasse hinzu, die die Auswahl unserer aktuellen Seite handhabt.
// BasePagination.vue
<template>
...
<BasePaginationTrigger
v-for="paginationTrigger in paginationTriggers"
:class="{
'base-pagination__description--current':
paginationTrigger === currentPage
}"
:key="paginationTrigger"
:pageNumber="paginationTrigger"
class="base-pagination__description"
@loadPage="onLoadPage"
/>
...
</template>
Und wir sind fertig! Wir haben gerade eine schöne und wiederverwendbare Paginierungskomponente in Vue erstellt.
Wann dieses Muster vermieden werden sollte
Obwohl diese Komponente ziemlich genial ist, ist sie kein Allheilmittel für alle Anwendungsfälle, die Paginierung betreffen.
Es ist zum Beispiel wahrscheinlich eine gute Idee, dieses Muster für Inhalte zu vermeiden, die ständig gestreamt werden und eine relativ flache Struktur haben, bei der jedes Element auf der gleichen Hierarchieebene liegt und eine ähnliche Chance hat, für den Benutzer interessant zu sein. Mit anderen Worten, weniger wie ein Artikel mit mehreren Seiten und mehr wie eine Hauptnavigation.
Ein weiteres Beispiel wäre das Durchsuchen von Nachrichten, anstatt nach einem bestimmten Nachrichtenartikel zu suchen. Wir müssen nicht wissen, wo sich die Nachricht genau befindet und wie weit wir gescrollt haben, um zu einem bestimmten Artikel zu gelangen.
Das ist ein Abschluss!
Hoffentlich ist dies ein Muster, das Sie in einem Projekt nützlich finden können, sei es für einen einfachen Blog, eine komplexe E-Commerce-Website oder etwas dazwischen. Paginierung kann mühsam sein, aber ein modulares Muster, das nicht nur wiederverwendet werden kann, sondern auch eine Vielzahl von Szenarien berücksichtigt, kann die Handhabung erheblich erleichtern.
Hallo, toller Artikel! Als ich jedoch den von Ihnen bereitgestellten Sandbox-Code getestet habe, habe ich
visiblePagesCountauf 4 geändert. Infolgedessen werden Dezimalzahlen in der Schaltfläche angezeigt. Zum Beispiel 1, 2.5, 3.5, 24. Wie kann das gelöst werden?