Knockout.js 在 if 绑定中使用 foreach 和 $index

Knockout.js using foreach and $index with if binding

我正在尝试显示 divs 3 x 3 内分组的迭代列表中的元素。我使用了 $index 的值,但我无法弄清楚为什么看起来不对。

<div class="row" data-bind="foreach: displaySel">
     <div class="col-md-2">
          <!--ko if: $index() % 3 === 0-->
          <div data-bind="attr:{id: 'div_'+$index()}">
          <!--/ko -->
               <div data-bind="attr:{id: 'g_'+$data.hId}" style="position:relative;">
                    <div>other things here</div>
               </div>
          <!--ko if: ($index() % 3 === 2 || $index() === displaySel.length - 1)-->
          </div>
          <!--/ko -->
    </div>
</div>

第一个 div 应该在第一个元素信息之前打开并在第三个元素信息之后关闭。第二个 div 将在第四个之前打开并在另外三个之后关闭,依此类推,直到列表结束。这里最好的方法是什么?

你不能(或者我忘记了不应该)以命令式的方式真正使用 Knockout,你可以手动生成或不生成 opening/closing 标签。相反,您需要正确嵌套。

换句话说,将 <!-- ko if: ... --><!-- /ko --> 视为正确的 close/end 标记,它们始终需要环绕 full 元素。

换句话说,您正在尝试执行与此等效的操作:

<div>
  Some content
  <strong>
    <div>
  </strong>

      CONTENT

  <strong>
    </div>
  </strong>
</p>

也许 Knockout 应该给你一个错误,但是(我猜本着 HTML 的精神)它会尽力利用它。

因此,您应该在视图模型中执行“分组”逻辑。额外的好处是您也可以对它进行单元测试。这是一个例子:

const chunkSize = 3;

class RootVm {
  displaySel = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
  displaySelGroups = ko.computed(() =>
    // Chunk in groups of 3 based on:
    // 
    [...Array(Math.ceil(this.displaySel.length / chunkSize))].map(_ => this.displaySel.splice(0,chunkSize))
  );
}

ko.applyBindings(new RootVm());
.col-2 { background: silver; border: 1px solid black; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.0/css/bootstrap.min.css" integrity="sha512-P5MgMn1jBN01asBgU0z60Qk4QxiXo86+wlFahKrsQf37c9cro517WzVSPPV1tDKzhku2iJ2FVgL67wG03SGnNA==" crossorigin="anonymous" />

<div class="row" data-bind="foreach: displaySelGroups">
  <div class="col-2" data-bind="foreach: $data">
    <div data-bind="attr:{id: 'div_'+$index()}">
      <div data-bind="attr:{id: 'g_'+$data.hId}" style="position:relative;">
        <div data-bind="text: $data"></div>
      </div>
    </div>
  </div>
</div>