如何处理Knockout的分页
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何处理Knockout的分页相关的知识,希望对你有一定的参考价值。
我有一个设置为绑定到observeableArray
的div,但我只想在任何给定时间显示来自该observeableArray
的最多50个项目。我想通过分页和上一个按钮以及页面上的索引来处理这个问题,以允许用户循环访问集合中的项目页面。
我知道我可能用computedObservable
和自定义数据绑定做到这一点,但我不知道该怎么做(我仍然是一个淘汰赛新手)。
谁能指出我正确的方向?
这是我的代码(JS在TypeScript中):
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<%=
if params[:q]
render 'active_search.html.erb'
else
render 'passive_search.html.erb'
end
%>
<%= form_tag("/search", method: "get", :class => "form-search form-inline") do %>
<%= label_tag(:q, "Search for:") %>
<%= text_field_tag(:q, nil, class:"input-medium search-query") %>
<%= submit_tag("Search", :class=>"btn") %>
<% end %>
<div class="media" data-bind="foreach: tweetsArray">
<%= image_tag('twitter-icon.svg', :class=>"tweet_img", :style=>"display:inline;") %>
<div class="media-body" style="display:inline;">
<h4 class="media-heading" data-bind="text: user.screen_name" style="display:inline;"></h4>
<span data-bind="text:text" style="display:inline;"></span> <br />
<span data-bind="text:'Created at '+created_at"></span> <br />
</div>
</div>
<div class="pagination pagination-centered">
<ul>
<li>
<a href="#">Prev</a>
</li>
<li>
<a href="#">1</a>
</li>
<li>
<a href="#">Next</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<script>
var viewModel = new twitterResearch.TweetViewModel();
ko.applyBindings(viewModel);
//TODO: notes to self, use custom binding for pagination along with a computed observable to determine where at in the list you are
//document.onReady callback function
$(function() {
$.getJSON('twitter', {}, function(data) {
viewModel.pushTweet(data);
console.log(data.user);
});
});
</script>
declare var $: any;
declare var ko: any;
module twitterResearch {
class Tweet {
text: string;
created_at: string;
coordinates: string;
user: string;
entities: string;
id: number;
id_str: string;
constructor(_text: string, _created_at: string, _coordinates: any, _user: any,
_entities: any, _id_str: string, _id: number){
this.text = _text;
this.created_at = _created_at;
this.coordinates = _coordinates;
this.user = _user;
this.entities = _entities;
this.id_str = _id_str;
this.id = _id;
}
}
export class TweetViewModel{
tweetsArray: any;
constructor()
{
this.tweetsArray = ko.observableArray([]);
}
//tweet is going to be the JSON tweet we return
//from the server
pushTweet(tweet)
{
var _tweet = new Tweet(tweet.text, tweet.created_at, tweet.coordinates,
tweet.user, tweet.entities, tweet.id_str, tweet.id);
this.tweetsArray.push(_tweet);
this.tweetsArray.valueHasMutated();
}
}
}
答案
使用Knockout进行分页非常简单。我个人会这样做:
- 有一个包含所有元素的observableArray
- 有一个包含当前页面的observable(初始化为0)
- 有一个变量声明每页的元素数量
- 有一个返回页数的计算器,由于每页元素数和元素总数计算得出。
- 最后,添加一个计算切片包含所有元素的数组。
鉴于此,您现在可以添加一个递增(下一个)或递减(前一个)当前页面的函数。
这是一个简单的例子:
var Model = function() {
var self = this;
this.all = ko.observableArray([]);
this.pageNumber = ko.observable(0);
this.nbPerPage = 25;
this.totalPages = ko.computed(function() {
var div = Math.floor(self.all().length / self.nbPerPage);
div += self.all().length % self.nbPerPage > 0 ? 1 : 0;
return div - 1;
});
this.paginated = ko.computed(function() {
var first = self.pageNumber() * self.nbPerPage;
return self.all.slice(first, first + self.nbPerPage);
});
this.hasPrevious = ko.computed(function() {
return self.pageNumber() !== 0;
});
this.hasNext = ko.computed(function() {
return self.pageNumber() !== self.totalPages();
});
this.next = function() {
if(self.pageNumber() < self.totalPages()) {
self.pageNumber(self.pageNumber() + 1);
}
}
this.previous = function() {
if(self.pageNumber() != 0) {
self.pageNumber(self.pageNumber() - 1);
}
}
}
你会在这里找到一个简单而完整的例子:http://jsfiddle.net/LAbCv/(可能有点儿马车,但想法就在那里)。
另一答案
实际上我正在一个网站上工作,这个网站有很多表(大多数都需要分页)。
实际上,我需要一些reusable-component
进行分页,以便在我需要分页的所有情况下使用它。
此外,我需要比此问题的接受答案中提供的更高级的功能。
所以我开发了自己的组件来解决这个问题,就在这里。
有关更多详细信息,请继续阅读(请考虑从GitHub获取代码,而不是从此处获取代码,因为GitHub代码已更新并增强,因为我将其放在此处)
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>
特征
- 显示需要
当根本不需要分页时(例如需要显示小于页面大小的项目),
HTML
组件将消失。 这将由statementdata-bind="visible: NeedPaging"
建立。 - 根据需要禁用
例如,如果您已经选择了最后一页,为什么要按
last page
或Next
按钮? 我正在处理这个,在这种情况下,我通过应用以下绑定data-bind="css: { disabled: !PreviousPageActive() }"
禁用这些按钮 - 区分所选页面
在所选页面上应用一个特殊类(在本例中称为
active
类),以使用户知道他/她现在在哪个页面。 这是由绑定data-bind="css: { active: $parent.CurrentPage() === $data }"
建立的 - 最后和第一 通过专门用于此的简单按钮也可以访问第一页和最后一页。
- 显示按钮的限制
假设你有很多页面,例如1000页,那么会发生什么?你会为用户显示它们吗?绝对不是你必须根据当前页面显示其中的一些。例如,显示所选页面之前的3页和其他3页。
这个案子已在这里处理
<!-- ko foreach: GetPages() -->
GetPages
函数应用一个简单的算法来确定我们是否需要显示所有页面(页面数量低于阈值,这可以很容易地确定),或者只显示一些按钮。 您可以通过更改maxPageCount
变量的值来确定阈值 现在我将它指定为以下var maxPageCount = 7;
,这意味着可以为用户显示不超过7个按钮(在SelectedPage之前3个,在Selected Page之后3个)和Selected Page本身。 您可能想知道,如果在当前页面显示之前OR之后没有足够的页面会怎么样?不要担心我在算法中处理这个问题 例如,如果您有11 pages
并且您有maxPageCount = 7
和当前的selected page is 10
,那么将显示以下页面5,6,7,8,9,10(selected page),11
因此,我们总是对maxPageCount
进行分层,在前面的示例中,在所选页面之前显示5
页面,在所选页面之后只显示1
页面。 - 选择页面验证
用户确定所选页面的
CurrentPage
observabl以上是关于如何处理Knockout的分页的主要内容,如果未能解决你的问题,请参考以下文章