【问题标题】:Placing a Container Around Every 'n' Items in a Knockout JS foreach Loop在 Knockout JS foreach 循环中的每个“n”项周围放置一个容器
【发布时间】:2015-07-22 18:27:06
【问题描述】:

我想使用淘汰赛 JS foreach 循环构造以下 HTML...

<div>
  <div>
    <article></article>
    <article></article>
    <article></article>
  </div>
  <div>
    <article></article>
    <article></article>
    <article></article>
  </div>
</div>

...其中每个“文章”都是数组中的一个项目。

我尝试了以下方法,这在逻辑上似乎合理,但它不起作用 - 我假设淘汰赛被 cmets 内的不平衡标签弄糊涂了...

<div data-bind="foreach: articles()">
  <!-- ko: if ($index() % 3 == 0)
    <div>
  <!-- /ko -->

    <article></article>

  <!-- ko: if ($index() % 3 == 2)
    </div>
  <!-- /ko -->
</div>

任何关于我如何实现这一目标的想法都将不胜感激!

【问题讨论】:

  • 我遇到了同样的问题,只是 theadtbody 我显然只想创建一次,基于 $index()。 KO 只能处理格式良好的元素。请注意,在绑定中使用括号将删除视图中数据绑定的自动更新:foreach: articles()。只需转到foreach: articles

标签: javascript knockout.js


【解决方案1】:

在处理类似问题时,我对此的看法一直是,视图模型的结构必须尽可能接近视图,这样您就不会在视图本身中执行逻辑。因此,对文章数组进行分组的地方是在视图模型中使用ko.computed 来构建如下结构:

groupedArticles = [
    [article1, article2, article3],
    [article4, article5, article6]
]

那么在你看来你可以这样做:

<!-- ko foreach: groupedArticles -->
<div>
    <!-- ko foreach: $data -->
    <article></article>
    <!-- /ko -->
</div>
<!-- /ko -->

让我知道这是否有意义;如果没有,我可以尝试添加一个小提琴来演示它。

更新

我找到了一个使用这种模式的小提琴。我需要将 KO 升级到最新版本才能使其正常工作,您现在可以使用以下方法进行尝试:http://jsfiddle.net/hFPgT/160/

这是来自问题,How to get Knockout to group foreach

而相关代码为:

this.grouped = ko.computed(function () {
        var rows = [], current = [];
        rows.push(current);
        for (var i = 0; i < this.items.length; i += 1) {
            current.push(this.items[i]);
            if (((i + 1) % 4) === 0) {
                current = [];
                rows.push(current);
            }
        }
        return rows;
}, this);

【讨论】:

  • 虽然这可行,但它并不漂亮,因为它将显示逻辑与数据混合在一起。
  • 你能解释更多吗?毕竟,视图模型并不完全是模型。它是将模型改编成适合在视图中渲染的结构。因此,根据其定义,它是将显示逻辑与数据混合的地方。如果你想获得更多的分离,一定要有一个单独的模型,然后是一个视图模型和一个视图。击退之类的框架可以做到这一点。
  • 根据 MVVM 范例,数据应该存储在模型中,由视图模型修改以供查看,并由视图显示。所以正确的方法是拥有一个单独的模型,然后在视图模型中使用该数据。
  • 我同意@sifriday。视图模型公开了要绑定到视图的属性,并且您可以在其中混合显示逻辑。你还会在哪里做呢?
【解决方案2】:

像@sifriday 一样,我会选择一个单独的计算数组,我将其命名为articleGroups(或视图)。在我最近对 ​​Knockout 的理解中,我发现将所有与视图相关的逻辑(这里:分组)放在组件的 viewModel 中最方便,所以我在这里为它构建了一个组件。 额外的好处是可以在视图中传递参数;例如,尝试下面的 sn-p 为 'groupBy' 设置不同的值。

// setup
var articles = [];
for (var i = 0; i < 50; i++)
  articles.push({i: i+1, text: "text"});

// listview component
ko.components.register('article-view', {
  viewModel: function(params) {
    var groupBy = this.groupBy = ko.observable(params.groupBy);
    this.articleGroups = ko.computed(function() {
      var result = [], group = groupBy();
      ko.utils.arrayForEach(ko.unwrap(params.data), function(item, index) {
        if (index % group === 0) 
          result.push([item]);
        else 
          result[result.length-1].push(item);
      });
      return result;
    });
  },
  template: {element: 'article-group'}
});

// viewModel instantiation
VM = { articles: ko.observableArray(articles)};
ko.applyBindings(VM);
body&gt;div&gt;div&gt;div { border-bottom: 1px solid gray; padding-bottom: 10px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<script type="text/template" id="article-group">
  <input type="number" data-bind="value: groupBy" min="1" max="50">
  <div data-bind="foreach: articleGroups, as: 'group'">
    <div data-bind="foreach: $data, event: {load: console.log($data)}">
      <article data-bind="text: i"></article>
    </div>
  </div>
</script>
<div data-bind="component: {name: 'article-view', params: {groupBy: 5, data: articles}}"></div>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多