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>
我正在尝试显示 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>