如何在数据绑定视图中模板 If-Else 结构?

我经常发现自己在基于 KO 的 HTML 模板中使用这个习惯用法:

<!-- ko if: isEdit -->
<td><input type="text" name="email" data-bind="value: email" /></td>
<!-- /ko -->
<!-- ko ifnot: isEdit -->
<td data-bind="text: email"></td>
<!-- /ko -->

在 KO 中有没有更好的/更简洁的方法来处理条件句,或者有没有比仅仅使用传统的 if-else 构造更好的 接近

此外,我想指出的是,一些版本的 Internet Explorer (IE8/9)没有正确解析上面的例子。有关详细信息,请参阅 这个所以问题。快速总结是,不要在表标记中使用注释(虚拟绑定)来支持 IE。改为使用 tbody:

<tbody data-bind="if: display"><tr><td>hello</td></tr></tbody>
81137 次浏览

One approach is to use named templates (which can support passing arguments):

<!-- ko template: isEdit() ? 'emailEdit' : 'emailDisplay' --><!-- /ko -->
<script id="emailEdit" type="text/html">
<td><input type="text" name="email" data-bind="value: email" /></td>
</script>
<script id="emailDisplay" type="text/html">
<td data-bind="text: email"></td>
</script>

Another option is use my switch/case plugin, which would work like this:

<!-- ko switch -->
<!-- ko case: isEdit -->
<td><input type="text" name="email" data-bind="value: email" /></td>
<!-- /ko -->
<!-- ko case: $else -->
<td data-bind="text: email"></td>
<!-- /ko -->
<!-- /ko -->

There are a couple different ways that you can handle this type of code.

  • with an if/ifnot combination like you are now. This works fine and is not terribly verbose.

  • Michael Best's switch/case binding (https://github.com/mbest/knockout-switch-case) is quite flexible and can let you easily handle this and more complicated ones (more states than true/false).

  • Another option is to use dynamic templates. You would bind an area to one or more templates with the template name being used based on an observable. Here is a post that I wrote on this topic a while back: http://www.knockmeout.net/2011/03/quick-tip-dynamically-changing.html. In your scenario, it might look like:

<td data-bind="template: $root.getCellTemplate"></td>


<script id="cellEditTmpl" type="text/html">
<input type="text" name="email" data-bind="value: email" />
</script>


<script id="cellTmpl" type="text/html">
<span data-bind="text: email"></span>
</script>

The getCellTemplate function could live wherever, but would be given the item ($data) as the first argument and would return the name of the template to use.

To avoid recalculation of knockout binding when using combination of if: / ifnot: you can use them in conjunction with 'with:' construction

    <!-- ko with: $data.DoSomePerformanceCriticalWork($data.SomeParameter()) -->
<!-- ko if: $data.Condition() -->
... some markup ...
<!-- /ko -->
<!-- ko ifnot: $data.Condition() -->
... some markup ...
<!-- /ko -->
<!-- /ko -->

There is now also the knockout-else binding/plugin (that I wrote to address this issue).