# 五、外观绑定

在上一章中，我们看到了 Quinch . js 的控制流绑定如何为视图代码提供一个基本的模板系统。控制流绑定为应用提供了可视化结构，但是一个成熟的模板系统需要的不仅仅是结构。knockout. js 的外观绑定让您可以精确控制单个元素的样式和格式。

在撰写本文时，knockout. js 附带了六个绑定来控制 HTML 元素的外观:

*   `text: <value>`—设置元素的内容。
*   `html: <value>`—设置元素的 HTML 内容。
*   `visible: <condition>`-根据特定条件显示或隐藏元素。
*   `css: <object>`—向元素添加 CSS 类。
*   `style: <object>`—定义元素的`style`属性。
*   `attr: <object>`—向元素添加任意属性。

像所有的 knockout. js 绑定一样，外观绑定总是出现在 HTML 元素的`data-bind`属性内部。但是与前一章的控制流绑定不同，外观绑定只影响它们相关的元素——它们不改变模板块或绑定上下文。

## 文本绑定

`text`绑定是敲除的基础。正如我们已经看到的，`text`绑定显示了 HTML 元素内部的属性值:

```js
            <td data-bind='text: name'></td>

```

您应该只在文本级元素上使用`text`绑定(例如，`<a>`、`<em>`、`<span>`等)。)，尽管从技术上讲，它可以应用于任何 HTML 元素。作为其参数，`text`绑定采用任何数据类型，并在呈现之前将其转换为字符串。`text`绑定将转义 HTML 实体，因此可以用来安全地显示用户生成的内容。

![](img/image016.png)

图 16:视图中自动转义的 HTML 实体的`text`绑定

还值得指出的是，knockout. js 在幕后管理跨浏览器问题。对于 IE，它使用`innerText`属性，对于火狐和相关浏览器，它使用`textContent`。

## html 绑定

`html`绑定允许您将字符串呈现为 HTML 标记。如果您想要在视图模型中动态生成标记并在模板中显示它，这将非常有用。例如，您可以在我们的`Product`对象上定义一个名为`formattedName`的计算可见性，它包含一些 HTML:

```js
        function Product(name, price, tags, discount) {       ...       this.formattedName = ko.computed(function() {         return "<strong>" + this.name() + "</strong>";       }, this);     }

```

然后，您可以使用`html`绑定呈现格式化名称:

```js
      <span data-bind='html: featuredProduct().formattedName'></span>

```

虽然这违背了将内容与呈现分开的目标，但是`html`绑定如果使用得当，可以证明是一个通用的工具。

![](img/image017.png)

图 17:视图中`html`绑定呈现 HTML 实体

无论何时渲染动态 HTML——无论是通过`html`绑定还是 ASP。NET—始终确保标记已经过验证。如果需要显示不可信的内容，应该使用`text`绑定，而不是`html`。

在前面的片段中，还要注意`featuredProduct`是一个可观测的对象，所以底层对象必须用空的函数调用来引用，而不是直接用`featuredProduct.formattedName`访问属性。同样，这是 knockout 初学者的常见错误。

## 可见绑定

很像`if`和`ifnot`绑定，`visible`绑定允许您根据特定条件显示或隐藏元素。但是，`visible`绑定并没有将元素从 DOM 中完全移除，而是简单地将一个`display: none`声明添加到元素的`style`属性中。例如，我们可以将现有的`if`绑定更改为`visible`绑定:

```js
            <td data-bind='visible: discount() > 0' style='color: red'>

```

下面的代码示例显示了`if`和`visible`版本的结果 HTML。本例假设条件评估为`false`:

```js
    <!-- Using if binding: --> <td data-bind="if: discount() > 0" style="color: red"></td>
     <!-- Using visible binding: --> <td data-bind='visible: discount() > 0'     style='color: red; display: none'>
      You saved <span data-bind='text: formattedDiscount'></span>!!! </td>

```

决定何时使用`visible`对`if`很大程度上取决于上下文。在这种情况下，实际上最好使用`if`绑定，这样空的`<td>`会为每行创建相同数量的列。

该绑定采用与`if`和`ifnot`绑定相同的参数。条件可以是视图模型的属性、JavaScript 表达式或返回布尔值的函数。

## css 绑定

`css`绑定允许您根据特定条件为 HTML 元素定义 CSS 类。它不是将条件作为参数，而是将包含 CSS 类名的对象作为属性名，将应用该类的条件作为值。这最好用一个例子来解释。

比方说，当一个产品的折扣超过 15%时，你想引起额外的注意。一种方法是在显示所有购物车商品的`<table>`中添加一个`css`绑定到“您保存 __%”消息:

样本代码:item016.htm

```js
            <td data-bind='if: discount() > 0' style='color: red'>
              You saved <span data-bind='text: formattedDiscount,                      css: {supersaver: discount() > .15}'></span>!!!
            </td>

```

首先，您会注意到，通过用逗号分隔，可以向单个`data-bind`属性添加多个绑定。第二，`css`绑定以`{supersaver: discount() > .15}`对象为论据。这就像一个映射，定义了什么时候应该将一个 CSS 类添加到元素中。在这种情况下，只要产品的折扣大于 15%，就会增加`.supersaver`类，否则会删除。定义`.supersaver`规则的实际 CSS 可以在页面的任何地方定义(即外部或内部样式表)。

```js
    .supersaver {
      font-size: 1.2em;
      font-weight: bold; }

```

如果你给第二个产品加 10%的折扣，你应该会看到我们的`css`绑定在起作用:

![](img/image018.png)

图 18:`discount() > .15`时`css`绑定应用类

对象属性中包含的条件与`if`、`ifnot`和`visible`绑定的参数相同。它可以是属性、JavaScript 表达式或函数。

## 装帧风格

`style`绑定提供了与`css`绑定相同的功能，除了它操纵元素的`style`属性，而不是添加或移除类。由于内联样式需要键值对，因此该绑定参数的语法也略有不同:

```js
              You saved <span data-bind='text: formattedDiscount,                      style: {fontWeight: discount() > .15 ? "bold" : "normal"}'></span>!!!

```

如果产品的折扣大于 15%，knockout. js 将把这个元素呈现如下:

```js
            <td style='color: red; font-weight: bold'>

```

但是，如果低于 15%，就会有`normal`的`font-weight`。请注意，`style`绑定可以与元素现有的`style`属性结合使用。

## 属性绑定

`attr`绑定允许您使用视图模型属性动态定义 HTML 元素的属性。例如，如果我们的`Product`类有一个`permalink`属性，我们可以通过以下方式生成到各个产品页面的链接:

```js
      <p><a data-bind='attr: {href: featuredProduct().permalink}'>View details</a></p>

```

这将向`<a>`标签添加一个`href`属性，指向存储在`permalink`属性中的任何内容。当然，如果`permalink`是一个可观测的，你可以利用 Denuke . js 的自动依赖跟踪的所有好处。由于永久链接通常与数据对象一起存储在永久存储器(例如，博客条目)中，因此以这种方式动态生成链接非常方便。

但是，`attr`绑定不仅仅是创建链接。它允许你在一个 HTML 元素中添加任何属性。这为将您的 knockout. js 模板与其他 DOM 库集成打开了各种各样的大门。

## 摘要

这一章介绍了 knockout. js 的外观绑定。当满足特定条件时，这些绑定中的许多会更改 HTML 元素。直接在绑定中定义这些条件是设计模板的一种直观方式，它将视图为中心的代码保持在视图模型之外。

请记住，knockout. js 的目标是通过在数据发生变化时自动同步视图，让您专注于应用背后的数据。一旦定义了绑定，就再也不用担心它们了(当然，除非您改变视图模型的结构)。

本章中展示的外观绑定提供了您需要的所有工具来*显示*您的数据，但是它们不允许我们向视图组件添加任何用户交互。在下一章中，我们将看一下 Dellow . js 是如何管理表单域的。