【问题标题】:How to properly create pagination with knockout.js component?如何使用 knockout.js 组件正确创建分页?
【发布时间】:2017-08-30 02:40:31
【问题描述】:

我正在为当前和未来的项目构建一个组件,用于处理淘汰组件级别的分页。我的想法是基于here 接受的答案。另请参考 Knockout 组件页面here

到目前为止,这是我的组件。我无法让任何数据实际显示,更不用说动态表格标题了。

ko.components.register("jPage", {
viewModel: function (params) {
    var self = this;
    self.Items = params.Items;
    self.Keys = Object.keys(self.Items);
    self.PerPage = params.PerPage;
    self.Page = 1;
    self.PagesTotal = Math.ceil(self.Items.length / self.PerPage);

    self.ItemsVisible = ko.computed(function () {
        first = (self.Page * self.PerPage) - self.PerPage;
        return self.Items.slice(first, first + self.PerPage);
    })

    self.ChangePage = function (_page) {
        if (_page < 1 || _page > self.PagesTotal) return;
        this.Page(_page);
    }.bind(this);


},
template: 
    '<div data-bind="foreach: ItemsVisible"> \
        Display Table headers and data here <br>\
        <span data-bind="text: $data[0]"> </span>\
    </div>\
    <nav aria-label="Page navigation">\
    <ul class="pagination">\
        <li data-bind="css:{disabled: Page <= 1} ">\
            <a aria-label="Previous" data-bind="click: ChangePage( Page - 1 )">\
                <span aria-hidden="true">&laquo;</span>\
            </a>\
        </li>\
        <li><a data-bind="text: Page -2, click: ChangePage( Page - 2 ), visible: Page > 2 "> </a></li>\
        <li><a data-bind="text: Page -1, click: ChangePage( Page - 1 ), visible: Page > 1 "> </a></li>\
        <li class="active"><a data-bind="text: Page"> </a></li>\
        <li><a data-bind="text: Page +1, click: ChangePage( Page + 1 ), visible: (PagesTotal > Page +0) "></a></li>\
        <li><a data-bind="text: Page +2, click: ChangePage( Page + 2 ), visible: (PagesTotal > Page +1)"></a></li>\
        <li data-bind="css: {disabled: (PagesTotal < Page )}">\
            <a aria-label="Next" data-bind="click: ChangePage( Page + 1 )">\
                <span aria-hidden="true">&raquo;</span>\
            </a>\
        </li>\
    </ul>\
</nav>\
'
})

这是组件的调用方式:

<div data-bind="component: { name: 'jPage', params: { Items: CustomerList(), PerPage: 25} }">

CustomerList 看起来像:

[
  {FirstName: "John", Email: "John@example.com"},
  {FirstName: "Steve", Email: "Steve@example.com"},
  {FirstName: "Jim", Email: "Jim@example.com"}
]

我缺少哪些变量或上下文来访问 Items 键/值?

附加说明。 我没有任何必需的数据形式,因为我可以毫无后果地操纵它。

【问题讨论】:

  • 首先为了对变化做出反应,属性必须是可观察的。因此,您的 Page 属性不会像现在这样发挥作用。一旦你解决了这个问题,然后是所有使用它的参考资料,你的很多问题都会消失。 knockoutjs.com/documentation/observables.html

标签: javascript knockout.js pagination


【解决方案1】:

好的。我花了 6 个月的时间才弄清楚这一点。但希望其他人会发现它和我一样有价值。

我发现的窍门不是使用组件,而是仅用于 HTML 的模板。虽然我猜一个组件也可以工作。

下面是用于分页的视图模型的代码及其工作原理的一个小示例。它只需要 1 个输入、一个数组,然后您只需绑定 PerPage,然后绑定输出 PaginatedArray 和 tah dah。

function MainViewModel() {
  var self = this;

  self.ListOfStuff = ko.observableArray();

  self.Pagination = ko.observable(new PaginationVM(self.ListOfStuff));

  self.PopulateArray = function() {
    for (var i = 0; i < 100; i++) {
      self.ListOfStuff.push("Item " + i);
    }
  }
  self.PopulateArray();
}


function PaginationVM(input) {
  var self = this;
  self.InputArray = input;
  self.PerPage = ko.observable();
  self.Page = ko.observable(1);

  self.PageTotal = ko.computed(function() {
    var totalPages = Math.ceil(self.InputArray().length / parseInt(self.PerPage()));
    if (self.Page() > totalPages && totalPages > 0) {
      self.Page(totalPages);
    }
    return totalPages
  })

  self.PaginatedArray = ko.computed(function() {
    var perPage = parseInt(self.PerPage())
    var start = self.Page() * perPage - perPage;
    return self.InputArray().slice(start, start + perPage);
  })

  self.ChangePageBy = function(offset) {
    return function() {
      self.Page(self.Page() + offset);
    }
  }

  self.ChangePageTo = function(newPage) {
    return function() {
      switch (newPage) {
        case "last":
          self.Page(self.PageTotal());
          break;
        case "first":
          self.Page(1);
          break;
        default:
          self.Page(newPage);
      }
    }
  }
}


ko.applyBindings(new MainViewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

<!-- This is the template needed for the view model but you can style it as necessary 
Its bootstrap right now.-->
<script type="text/html" id="PaginationTemplate">
  <nav class="text-center" aria-label="Page navigation">
    <ul class="pagination" style="cursor:pointer">
      <li data-bind="css:{disabled: Page() <= 1} ">
        <a aria-label="Previous" data-bind="click: ChangePageTo('first')">
          <span aria-hidden="true">&laquo;</span>
        </a>
      </li>
      <li>
        <a data-bind="text: Page() -2, click: ChangePageBy(-2), visible: Page() > 2 "> </a>
      </li>
      <li>
        <a data-bind="text: Page() -1, click: ChangePageBy(-1), visible: Page() > 1 "> </a>
      </li>
      <li class="active">
        <a data-bind="text: Page() "> </a>
      </li>
      <li>
        <a data-bind="text: Page() +1, click: ChangePageBy(1), visible: (PageTotal() > Page() +0)"></a>
      </li>
      <li>
        <a data-bind="text: Page() +2, click: ChangePageBy(2), visible: (PageTotal() > Page() +1)"></a>
      </li>

      <li data-bind="css: {disabled: (PageTotal() < Page() +1)}">
        <a aria-label="Next" data-bind="click: ChangePageTo('last')">
          <span aria-hidden="true">&raquo;</span>
        </a>
      </li>
    </ul>
  </nav>
</script>


<!-- This is what it looks like without pagination.
<div data-bind="foreach: ListOfStuff">
  <span data-bind="text: $data"> </span><br>
</div>-->
<select data-bind="value: Pagination().PerPage">
                                <option value="10">10</option>
                                <option value="25">25</option>
                                <option value="50">50</option>
                                <option value="100">100</option>
                            </select>
<div data-bind="foreach: Pagination().PaginatedArray">
  <span data-bind="text: $data"></span><br>
</div>
<div data-bind="template: { name : 'PaginationTemplate', data: Pagination }">

【讨论】:

    猜你喜欢
    • 2013-04-12
    • 2017-12-21
    • 2023-03-05
    • 1970-01-01
    • 2021-09-16
    • 1970-01-01
    • 2017-10-19
    • 2018-04-15
    • 1970-01-01
    相关资源
    最近更新 更多