Attualmente sto lavorando a un sito Web, che ha un sacco di tabelle (la maggior parte ha bisogno di paging).
Quindi, in realtà, avevo bisogno di un po 'di reusable-component
per il paging per usarlo in tutti i casi in cui ho bisogno di cercapersone.
Inoltre, avevo bisogno di funzionalità più avanzate di quelle fornite nella risposta accettata a questa domanda.
Così ho sviluppato il mio componente per risolvere questo problema, eccolo.
Now on Github
JsFiddle
E per maggiori dettagli, continuare a leggere (Si prega di prendere in considerazione di prendere il codice da GitHub, non da qui, come il codice GitHub è stato aggiornato e migliorato da quando ho metterlo qui)
JavaScript
function PagingVM(options) {
var self = this;
self.PageSize = ko.observable(options.pageSize);
self.CurrentPage = ko.observable(1);
self.TotalCount = ko.observable(options.totalCount);
self.PageCount = ko.pureComputed(function() {
return Math.ceil(self.TotalCount()/self.PageSize());
});
self.SetCurrentPage = function (page) {
if (page < self.FirstPage)
page = self.FirstPage;
if (page > self.LastPage())
page = self.LastPage();
self.CurrentPage(page);
};
self.FirstPage = 1;
self.LastPage = ko.pureComputed(function() {
return self.PageCount();
});
self.NextPage = ko.pureComputed(function() {
var next = self.CurrentPage() + 1;
if (next > self.LastPage())
return null;
return next;
});
self.PreviousPage = ko.pureComputed(function() {
var previous = self.CurrentPage() - 1;
if (previous < self.FirstPage)
return null;
return previous;
});
self.NeedPaging = ko.pureComputed(function() {
return self.PageCount() > 1;
});
self.NextPageActive = ko.pureComputed(function() {
return self.NextPage() != null;
});
self.PreviousPageActive = ko.pureComputed(function() {
return self.PreviousPage() != null;
});
self.LastPageActive = ko.pureComputed(function() {
return (self.LastPage() != self.CurrentPage());
});
self.FirstPageActive = ko.pureComputed(function() {
return (self.FirstPage != self.CurrentPage());
});
// this should be odd number always
var maxPageCount = 7;
self.generateAllPages = function() {
var pages = [];
for (var i = self.FirstPage; i <= self.LastPage() ; i++)
pages.push(i);
return pages;
};
self.generateMaxPage = function() {
var current = self.CurrentPage();
var pageCount = self.PageCount();
var first = self.FirstPage;
var upperLimit = current + parseInt((maxPageCount - 1)/2);
var downLimit = current - parseInt((maxPageCount - 1)/2);
while (upperLimit > pageCount) {
upperLimit--;
if (downLimit > first)
downLimit--;
}
while (downLimit < first) {
downLimit++;
if (upperLimit < pageCount)
upperLimit++;
}
var pages = [];
for (var i = downLimit; i <= upperLimit; i++) {
pages.push(i);
}
return pages;
};
self.GetPages = ko.pureComputed(function() {
self.CurrentPage();
self.TotalCount();
if (self.PageCount() <= maxPageCount) {
return ko.observableArray(self.generateAllPages());
} else {
return ko.observableArray(self.generateMaxPage());
}
});
self.Update = function (e) {
self.TotalCount(e.TotalCount);
self.PageSize(e.PageSize);
self.SetCurrentPage(e.CurrentPage);
};
self.GoToPage = function (page) {
if (page >= self.FirstPage && page <= self.LastPage())
self.SetCurrentPage(page);
}
self.GoToFirst = function() {
self.SetCurrentPage(self.FirstPage);
};
self.GoToPrevious = function() {
var previous = self.PreviousPage();
if (previous != null)
self.SetCurrentPage(previous);
};
self.GoToNext = function() {
var next = self.NextPage();
if (next != null)
self.SetCurrentPage(next);
};
self.GoToLast = function() {
self.SetCurrentPage(self.LastPage());
};
}
HTML
<ul data-bind="visible: NeedPaging" class="pagination pagination-sm">
<li data-bind="css: { disabled: !FirstPageActive() }">
<a data-bind="click: GoToFirst">First</a>
</li>
<li data-bind="css: { disabled: !PreviousPageActive() }">
<a data-bind="click: GoToPrevious">Previous</a>
</li>
<!-- ko foreach: GetPages() -->
<li data-bind="css: { active: $parent.CurrentPage() === $data }">
<a data-bind="click: $parent.GoToPage, text: $data"></a>
</li>
<!-- /ko -->
<li data-bind="css: { disabled: !NextPageActive() }">
<a data-bind="click: GoToNext">Next</a>
</li>
<li data-bind="css: { disabled: !LastPageActive() }">
<a data-bind="click: GoToLast">Last</a>
</li>
</ul>
Caratteristiche
Mostra sulla necessità
quando non c'è bisogno di paginazione a tutti (per esempio, gli elementi che devono visualizzare meno della dimensione della pagina), quindi il componente HTML
verrà disattivato apparire.
Questo sarà stabilito dalla dichiarazione data-bind="visible: NeedPaging"
.
Disabilita sulla necessità
per esempio, se si è già selezionata l'ultima pagina, perché il last page
o il pulsante Next
dovrebbe essere disponibile a premere?
sto manipolazione di questo e in quel caso io sto disabilitando quei bottoni applicando la seguente vincolantedata-bind="css: { disabled: !PreviousPageActive() }"
Distinguere la pagina selezionata
una classe speciale (in questo caso chiamato active
classe) viene applicata sulla pagina selezionata, per far sapere all'utente in quale pagina si trova adesso.
Questo è stabilito dal legame data-bind="css: { active: $parent.CurrentPage() === $data }"
Ultima & Prima
andare alla prima e l'ultima pagina è disponibile da semplici pulsanti dedicati a questo anche.
Limiti per pulsanti visualizzati
Supponiamo di avere un sacco di pagine, per esempio, 1000 pagine, allora che cosa succederà? li mostreresti tutti per l'utente? assolutamente non devi visualizzare solo alcuni di loro in base alla pagina corrente. per esempio, mostrando 3 pagine prima e altre 3 pagine dopo la pagina selezionata. <!-- ko foreach: GetPages() -->
la funzione GetPages
che applica un semplice algoritmo per determinare se è necessario mostrare tutte le pagine (il numero di pagine è sotto la soglia, che può essere determinato facilmente) o per mostrare solo alcune delle i pulsanti.
è possibile determinare la soglia modificando il valore della variabile maxPageCount
In questo momento l'ho assegnato come il seguente var maxPageCount = 7;
che significa che non possono essere visualizzati più di 7 pulsanti per l'utente (3 prima di SelectedPage e 3 dopo il Pagina selezionata) e la Pagina selezionata stessa.
Ci si potrebbe chiedere, cosa succederebbe se non ci fossero pagine sufficienti dopo O prima che venga visualizzata la pagina corrente? non ti preoccupare io sono la manipolazione di questo nell'algoritmo di
per esempio, se si dispone di 11 pages
e si ha maxPageCount = 7
e la corrente selected page is 10
, quindi verrà visualizzata nelle pagine seguenti
5,6,7,8,9,10(selected page),11
quindi abbiamo sempre stratificazione del maxPageCount
, nell'esempio precedente che mostra le pagine 5
prima della pagina selezionata e solo la pagina 1
dopo la pagina selezionata.
Selezionato pagina Convalida
Tutte le operazioni insieme per la CurrentPage
osservabile che determinano la pagina selezionata dall'utente, sta attraversando la funzione SetCurrentPage
. Solo in questa funzione impostiamo questa funzione osservabile e, come puoi vedere dal codice, prima di impostare il valore eseguiamo le operazioni di convalida per assicurarci che non andremo oltre la pagina disponibile delle pagine.
già pulito
Io uso solo pureComputed
non computed
proprietà, il che significa che non c'è bisogno di preoccuparsi se stessi con la pulizia e lo smaltimento di tali proprietà. Anche se, come si vedrà nel seguente esempio, è necessario disporre di alcuni altri abbonamenti che sono al di fuori del componente stesso
NOTA 1
Si può notare che sto usando un po 'di bootstrap
classi in questo componente, Questo è adatto per me, ma , ovviamente, è possibile utilizzare le proprie classi anziché le classi di bootstrap.
Le classi bootstrap che ho usato qui sono pagination
, pagination-sm
, active
e disabled
Sentitevi liberi di cambiarli come avete bisogno.
NOTA 2
Così ho introdotto il componente per voi, è il momento di vedere come potrebbe funzionare.
Integrare questo componente nel ViewModel principale come in questo modo.
function MainVM() {
var self = this;
self.PagingComponent = ko.observable(new Paging({
pageSize: 10, // how many items you would show in one page
totalCount: 100, // how many ALL the items do you have.
}));
self.currentPageSubscription = self.PagingComponent().CurrentPage.subscribe(function (newPage) {
// here is the code which will be executed when the user changes the page.
// you can handle this in the way you need.
// for example, in my case, I am requesting the data from the server again by making an ajax request
// and then updating the component
var data = /*bring data from server , for example*/
self.PagingComponent().Update({
// we need to set this again, why? because we could apply some other search criteria in the bringing data from the server,
// so the total count of all the items could change, and this will affect the paging
TotalCount: data.TotalCount,
// in most cases we will not change the PageSize after we bring data from the server
// but the component allows us to do that.
PageSize: self.PagingComponent().PageSize(),
// use this statement for now as it is, or you have to made some modifications on the 'Update' function.
CurrentPage: self.PagingComponent().CurrentPage(),
});
});
self.dispose = function() {
// you need to dispose the manual created subscription, you have created before.
self.currentPageSubscription.dispose();
}
}
Ultimo ma non meno importante, Certo non dimenticate di cambiare l'associazione nel componente HTML in base al vostro ViewModel speciale, o avvolgere tutta la componente con il with binding
come questo
<div data-bind="with: PagingComponent()">
<!-- put the component here -->
</div>
Acclamazioni
Questo è fantastico .. Grazie! L'ho espanso per mostrare ogni numero di pagina e consentire all'utente di fare clic da pagina 5 per dire pagina 1. http://jsfiddle.net/LAbCv/31/ –
Elimina l'ultima metà di una pagina, giusto? 'Math.ceil' dovrebbe essere nel calcolo del numero di pagine piuttosto che in' Math.floor'? modifica: Ahh si aggiunge il resto/modulo indietro, vorrei solo ceiling e fatto. – MrYellow
Stai attento a questo approccio se stai lavorando con qualsiasi cosa possa avere un set di risultati considerevole. Non è una buona idea caricare l'intero elenco di risultati lato client e quindi solo la pagina in javascript. Per set di risultati di grandi dimensioni, è necessario un qualche tipo di soluzione AJAX che carichi solo i dati necessari per la pagina corrente. – Mir