Knockout.js绑定可以同时应用于容器标签和后代吗?

Can Knockout.js bindings apply to container tags AND descendants both?

本文关键字:标签 后代 应用于 绑定 js Knockout      更新时间:2023-09-26

让我用一个简单的例子来设置这个问题。

我有一个HTML表,其中的行由observableArray控制。

如果observableArray里面没有元素,我想用一行来表示。我尝试了这个标记,"kind"可以工作:

<tbody data-bind="if: $root.data.contacts().length == 0">
    <tr>
        <td>There are no contacts specified yet.</td>
    </tr>
</tbody>
<tbody data-bind="foreach: $root.data.contacts">
        SNIP - a tbody with the rows is here when elements > zero
</tbody>

当我说"有点"的时候,我的意思是明显的。它确实在0个元素处出现并且在大于0个元素处消失就像你期望的那样。但是,当您打开DOM检查器(开发工具)并查看内存中的DOM时,您会发现有两个tbody节,而不是一个。现在一个tbody当然总是空的,但是

两个tbody标签不是HTML5正确的,所以这必须固定这不是期望的标记。

作为一个Knockout新手,我试图用一个虚拟元素来解决这个问题:

<!-- ko if: $root.data.contacts().length == 0 -->
<tbody>
    <tr>
        <td>There are no contacts specified yet.</td>
    </tr>
</tbody>
<!-- /ko -->

不幸的是,这在我们的构建过程中不起作用:我们在压缩之前缩小了HTML,并且消除了注释。

我的印象是KO绑定应用于CONTAINER ELEMENT本身以及后代,但事实似乎并非如此。是否有一种方法可以告诉KO应用于容器元素以及子元素,或者我是否需要以虚拟容器以外的方式更改标记?

和您一样,我的首选是if绑定的虚拟标记。但既然这不是一个选项,那么可交换模板呢?

var vm = {
  contacts: ko.observableArray()
};
ko.applyBindings(vm);
setTimeout(function() {
  vm.contacts(['One', 'Two', 'Three']);
}, 2500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
<template id="empty-body">
  <tbody>
    <tr>
      <td>There are no contacts specified yet.</td>
    </tr>
  </tbody>
</template>
<template id="normal-body">
  <tbody data-bind="foreach: contacts">
    <tr>
      <td data-bind="text:$data"></td>
    </tr>
  </tbody>
</template>
<table data-bind="template: contacts().length === 0 ? 'empty-body' : 'normal-body'"></table>

Knockout-Repeat绑定将该绑定应用于元素本身。它是通过使用节点预处理器在运行时将带有repeat绑定的元素包装在虚拟(基于注释)元素中来实现的。

var vm = {
  contacts: ko.observableArray()
};
ko.applyBindings(vm);
setTimeout(function() {
  vm.contacts(['One', 'Two', 'Three']);
}, 2500);
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.3.0/knockout-min.js"></script>
<script src="https://rawgit.com/mbest/knockout-repeat/master/knockout-repeat.js"></script>
<table>
  <tbody data-bind="repeat: !contacts().length && 1">
    <tr>
      <td>There are no contacts specified yet.</td>
    </tr>
  </tbody>
  <tbody data-bind="repeat: contacts().length && 1" data-repeat-bind="foreach: contacts">
    <tr>
      <td data-bind="text:$data"></td>
    </tr>
  </tbody>
</table>