JSON数据(test.json)
[{
"name": "A Goofy Movie (1995) 720p HDTVRip x264 Eng Subs [Dual Audio] [Hindi DD 2.0 - English DD 2.0] Exclusive By -=!Dr.STAR!=-",
"progress": 0,
"size": "1.06 GB",
"downloaded": "87.98 KB",
"hash": "8fe65e43464debe1bc0961e4656ea780368d4fba",
"peer": 0,
"delete": "delete.php?del=8fe65e43464debe1bc0961e4656ea780368d4fba",
"speed": "0 Byte",
"eta": "23:59:59",
"path": "C:\\xampp\\htdocs\\final\\download\/8fe65e43464debe1bc0961e4656ea780368d4fba"
}, {
"name": "Logan+2017+HDCAM+XviD+UnKnOwN",
"progress": 0,
"size": "0 Byte",
"downloaded": "0 Byte",
"hash": "624911f8e4fc172e5ed7970d3bc097198bfd4e76",
"peer": 0,
"delete": "delete.php?del=624911f8e4fc172e5ed7970d3bc097198bfd4e76",
"speed": "0 Byte",
"eta": "23:59:59",
"path": "C:\\xampp\\htdocs\\final\\download\/624911f8e4fc172e5ed7970d3bc097198bfd4e76"
}, {
"name": "Internet Download Manager 6.27 Build 5 Multilingual + Patch",
"progress": 100,
"size": "6.97 MB",
"downloaded": "7.49 MB",
"hash": "bffe600ae08ba8e55db30dae6acd86979e30ce15",
"peer": 0,
"delete": "delete.php?del=bffe600ae08ba8e55db30dae6acd86979e30ce15",
"speed": "0 Byte",
"eta": "23:59:59",
"path": "C:\\xampp\\htdocs\\final\\download\/bffe600ae08ba8e55db30dae6acd86979e30ce15"
}]
KnockoutJS数据
function ExampleViewModel() {
var self = this;
self.ExampleData = ko.observableArray([]);
self.update = function() {
$.ajax("test.json", {
success: function(allData) {
var mappeddata = $.map(allData, function(item) {
return new DataItem(item)
});
self.ExampleData(mappeddata);
}
});
}
}
function DataItem(data) {
ko.observable(data.name);
ko.observable(data.progress);
}
var exampleViewModel = new ExampleViewModel();
ko.applyBindings(exampleViewModel);
如何提供分页并仅显示前两个值?
答案 0 :(得分:1)
您可以从self.Data
下方
function ExampleViewModel() {
var self = this;
self.ExampleData = ko.observableArray([]);
self.CurrentPage = ko.observable(1);
self.DataPerPage = ko.observable(2); // You can change from here if you want to show the data other than 2 per page
self.Data = ko.pureComputed(function(){
var startIndex = self.CurrentPage() === 1? 0 : (self.CurrentPage() - 1) * self.DataPerPage();
return self.ExampleData().slice(startIndex, startIndex + self.DataPerPage())
});
self.update = function() {
$.ajax("test.json", {
success: function(allData) {
var mappeddata = $.map(allData, function(item) {
return new DataItem(item)
});
self.ExampleData(mappeddata);
}
});
}
}
简单示例:
function ViewModel() {
var self = this;
self.ExampleData = ko.observableArray([1, 2, 3, 4, 5, 6, 7, 8, 9]);
self.CurrentPage = ko.observable(1); // Store the current page of the user
self.DataPerPage = ko.observable(2); // To identify how many data we want to see per page
self.Data = ko.pureComputed(function(){
var startIndex = self.CurrentPage() === 1? 0 : (self.CurrentPage() - 1) * self.DataPerPage();
return self.ExampleData().slice(startIndex, startIndex + self.DataPerPage ())
});
self.Next = function() {
var totalData = self.ExampleData().length;
var currentPage = self.CurrentPage();
// if the length is 0, don't allow next
// if we're on the last page, don't allow next
if(totalData >= 1 && currentPage < (Math.ceil(totalData/2))) self.CurrentPage(currentPage + 1);
};
self.Prev = function() {
var currentPage = self.CurrentPage();
// if we're on the first page, don't allow prev
if(currentPage > 1) self.CurrentPage(currentPage - 1);
};
}
$(document).ready(function () {
var myViewModel = new ViewModel();
ko.applyBindings(myViewModel);
});
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<div>
<ul data-bind="foreach: Data">
<li data-bind="text: $data"></li>
</ul>
<button data-bind="click: Next">Next</button>
<button data-bind="click: Prev ">Prev</button>
</div>
&#13;
答案 1 :(得分:0)
实际上我在网站上工作,它有很多表(大多数都需要分页),所以实际上我需要一些reusable-component
来进行分页,以便在我需要分页的所有情况下使用它。
此外,我还需要比此问题的接受答案中提供的更多高级功能。
所以我在这个问题上开发了自己的组件,就在这里。
<强> Now on Github 强>
<强> JsFiddle 强>
有关详细信息,请继续阅读
<强>的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>
功能强>
显示需要
当根本不需要分页时(例如需要显示小于页面大小的项目),{{1} }组件将消失。
这将由声明HTML
确定。
根据需要禁用
例如,如果您已经选择了最后一页,为什么要按data-bind="visible: NeedPaging"
或last page
按钮?
我正在处理此问题,在这种情况下,我通过应用以下绑定来禁用这些按钮 Next
区分所选页面
在所选页面上应用一个特殊类(在本例中称为data-bind="css: { disabled: !PreviousPageActive() }"
类),以使用户知道他/她现在在哪个页面中。
这是通过绑定active
最后&amp;首先
通过专门用于此的简单按钮也可以访问第一页和最后一页。
显示按钮的限制
假设你有很多页面,例如1000页,那会发生什么?你会为用户显示它们吗? 绝对不你必须根据当前页面只显示其中一些。例如,在页面页面之前显示3页,在所选页面之后显示其他3页。
此案件已在此处理data-bind="css: { active: $parent.CurrentPage() === $data }"
<!-- ko foreach: GetPages() -->
函数应用一个简单的算法来确定我们是否需要显示所有页面(页面数量低于阈值,可以很容易地确定),或者只显示一些按钮。
您可以通过更改GetPages
变量的值来确定阈值
现在我将它指定为以下maxPageCount
,这意味着可以为用户显示不超过7个按钮(在SelectedPage之前为3,在Selected Page之后为3)和Selected Page本身。
您可能想知道,如果在当前页面显示之前 OR 之后没有足够的页面会怎么样? 不要担心我在算法中处理此问题例如,如果您有var maxPageCount = 7;
并且您有11 pages
和当前maxPageCount = 7
,那么以下页面将显示
selected page is 10
所以我们总是将5,6,7,8,9,10(selected page),11
分层,在上一个示例中,在所选页面之前显示maxPageCount
页面,在所选页面之后只显示5
页面。
所选页面验证
1
可观察的所有设置操作(用户确定所选页面)都通过函数CurrentPage
。在这个函数中,我们设置了这个可观察的,从代码中可以看出,在设置值之前,我们进行验证操作,以确保我们不会超出页面的可用页面。
已经清洁
我只使用SetCurrentPage
而非pureComputed
属性,这意味着您无需为清理和处理这些属性而烦恼。 虽然,正如您将在下面的示例中看到的那样,您需要处理组件本身之外的一些其他订阅
注1
您可能会注意到我在此组件中使用了一些computed
类,
这对我来说很合适,但当然你可以使用自己的类而不是bootstrap类。
我在这里使用的引导类是bootstrap
,pagination
,pagination-sm
和active
随意根据需要更改它们。
注2
所以我为你介绍了这个组件,是时候看看它是如何工作的。
您可以将此组件集成到主ViewModel中,如下所示。
disabled
最后但并非最不重要的,当然不要忘记根据您的特殊viewModel更改html组件中的绑定,或者使用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 change 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 allow 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();
}
}
这样包装所有组件
with binding
干杯