入门

监控属性

使用内置绑定

控制文本和外观

绑定逻辑控制

处理表单属性

解析模板

高级应用

插件

更多信息

"template" 绑定

目的

template 绑定将数据填充到关联的DOM模板中。模板是一个构建复杂用户界面的简单方式。

The template binding populates the associated DOM element with the results of rendering a template. Templates are a simple and convenient way to build sophisticated UI structures - possibly with repeating or nested blocks - as a function of your view model data.

使用模板主要有两个途径:

  • 母版是在HTML元素中包含 foreachifwith, 和其他流程控制绑定。并使用它们作为模板的呈现对象,此为Knockout内置功能不需要引用其他外部库。
  • 字符串解析模板是一个 Knockout 连接到第三方模板引擎的方法。 Knockout will pass your model values to the external template engine and inject the resulting markup string into your document. See below for examples that use the jquery.tmpl and Underscore template engines.
  • Native templating is the mechanism that underpins foreach, if, with, and other control flow bindings. Internally, those control flow bindings capture the HTML markup contained in your element, and use it as a template to render against an arbitrary data item. This feature is built into Knockout and doesn’t require any external library.
  • String-based templating is a way to connect Knockout to a third-party template engine. Knockout will pass your model values to the external template engine and inject the resulting markup string into your document. See below for examples that use the jquery.tmpl and Underscore template engines.

Parameters

  • Main parameter

    • Shorthand syntax: If you just supply a string value, KO will interpret this as the ID of a template to render. The data it supplies to the template will be your current model object.

    • For more control, pass a JavaScript object with some combination of the following properties:

      • name — the ID of an element that contains the template you wish to render - see Note 4 for how to vary this programmatically.
      • data — an object to supply as the data for the template to render. If you omit this parameter, KO will look for a foreach parameter, or will fall back on using your current model object.
      • foreach — instructs KO to render the template in “foreach” mode - see Note 2 for details.
      • afterRender, afterAdd, or beforeRemove — callback functions to be invoked against the rendered DOM elements - see Note 3

Note 1: Rendering a named template

Normally, when you’re using control flow bindings (foreach, with, if, etc.), there’s no need to give names to your templates: they are defined implicitly and anonymously by the markup inside your DOM element. But if you want to, you can factor out templates into a separate element and then reference them by name:

  1. <h2>Participants</h2>
  2. Here are the participants:
  3. <div data-bind="template: { name: 'person-template', data: buyer }"></div>
  4. <div data-bind="template: { name: 'person-template', data: seller }"></div>
  5. <script type="text/html" id="person-template">
  6. <h3 data-bind="text: name"></h3>
  7. <p>Credits: <span data-bind="text: credits"></span></p>
  8. </script>
  9. <script type="text/javascript">
  10. function MyViewModel() {
  11. this.buyer = { name: 'Franklin', credits: 250 };
  12. this.seller = { name: 'Mario', credits: 5800 };
  13. }
  14. ko.applyBindings(new MyViewModel());
  15. </script>

In this example, the person-template markup is used twice: once for buyer, and once for seller. Notice that the template markup is wrapped in a — the dummy type attribute is necessary to ensure that the markup is not executed as JavaScript, and Knockout does not attempt to apply bindings to that markup except when it is being used as a template.

It’s not very often that you’ll need to use named templates, but on occasion it can help to minimise duplication of markup.

Note 2: Using the “foreach” option with a named template

If you want the equivalent of a foreach binding, but using a named template, you can do so in the natural way:

  1. <h2>Participants</h2>
  2. Here are the participants:
  3. <div data-bind="template: { name: 'person-template', foreach: people }"></div>
  4. <script type="text/html" id="person-template">
  5. <h3 data-bind="text: name"></h3>
  6. <p>Credits: <span data-bind="text: credits"></span></p>
  7. </script>
  8. function MyViewModel() {
  9. this.people = [
  10. { name: 'Franklin', credits: 250 },
  11. { name: 'Mario', credits: 5800 }
  12. ]
  13. }
  14. ko.applyBindings(new MyViewModel());

This gives the same result as embedding an anonymous template directly inside the element to which you use foreach, i.e.:

  1. <div data-bind="foreach: people">
  2. <h3 data-bind="text: name"></h3>
  3. <p>Credits: <span data-bind="text: credits"></span></p>
  4. </div>

Note 3: Using “afterRender”, “afterAdd”, and “beforeRemove”

Sometimes you might want to run custom post-processing logic on the DOM elements generated by your templates. For example, if you’re using a JavaScript widgets library such as jQuery UI, you might want to intercept your templates’ output so that you can run jQuery UI commands on it to transform some of the rendered elements into date pickers, sliders, or anything else.

Generally, the best way to perform such post-processing on DOM elements is to write a custom binding, but if you really just want to access the raw DOM elements emitted by a template, you can use afterRender.

Pass a function reference (either a function literal, or give the name of a function on your view model), and Knockout will invoke it immediately after rendering or re-rendering your template. If you’re using foreach, Knockout will invoke your afterRender callback for each item added to your observable array. For example,

  1. <div data-bind='template: { name: "personTemplate",
  2. data: myData,
  3. afterRender: myPostProcessingLogic }'> </div>

… and define a corresponding function on your view model (i.e., the object that contains myData):

  1. viewModel.myPostProcessingLogic = function(elements) {
  2. // "elements" is an array of DOM nodes just rendered by the template
  3. // You can add custom post-processing logic here
  4. }

If you are using foreach and only want to be notified about elements are specifically being added or are being removed, you can use afterAdd and beforeRemove instead. For details, see documentation for the foreach binding.

Note 4: Dynamically choosing which template is used

If you have multiple named templates, you can use a callback function to determine which one of them is used. This can be accomplished by supplying a function for the name option. If you’re using the foreach template mode, Knockout will evaluate the function for each item in your array, passing that item’s value as the only argument. Otherwise, the function will be given the data option’s value or fall back to providing your whole current model object.

For example,

  1. <ul data-bind='template: { name: displayMode,
  2. foreach: employees }'> </ul>
  3. var viewModel = {
  4. employees: ko.observableArray([
  5. { name: "Kari", active: ko.observable(true) },
  6. { name: "Brynn", active: ko.observable(false) },
  7. { name: "Nora", active: ko.observable(false) }
  8. ]),
  9. displayMode: function(employee) {
  10. return employee.active() ? "active" : "inactive"; // Initially "Kari" uses the "active" template, while the others use "inactive"
  11. }
  12. };
  13. // ... then later ...
  14. viewModel.employees()[1].active(true); // Now "Brynn" is also rendered using the "active" template.

If your function references observable values, then the binding will update whenever any of those values change. This will cause the data to be re-rendered using the appropriate template.

Note 5: Using jQuery.tmpl, an external string-based template engine

In the vast majority of cases, Knockout’s native templating and the foreach, if, with and other control flow bindings will be all you need to construct an arbitrarily sophisticated UI. But in case you wish to integrate with an external templating library, such as the Underscore template engine or jquery.tmpl, Knockout offers a way to do it.

By default, Knockout comes with support for jquery.tmpl. To use it, you need to reference the following libraries, in this order:

  1. <!-- First jQuery --> <script src="http://code.jquery.com/jquery-1.7.1.min.js"></script>
  2. <!-- Then jQuery.tmpl --> <script src="http://github.com/downloads/SteveSanderson/knockout/jquery.tmpl.js"></script>
  3. <!-- Then Knockout --> <script src="knockout-x.y.z.js"></script>

Then, you can use jQuery.tmpl syntax in your templates. For example,

  1. <h1>People</h1>
  2. <div data-bind="template: 'peopleList'"></div>
  3. <script type="text/html" id="peopleList">
  4. {{each people}}
  5. <p>
  6. <b>${name}</b> is ${age} years old
  7. </p>
  8. {{/each}}
  9. </script>
  10. <script type="text/javascript">
  11. var viewModel = {
  12. people: ko.observableArray([
  13. { name: 'Rod', age: 123 },
  14. { name: 'Jane', age: 125 },
  15. ])
  16. }
  17. ko.applyBindings(viewModel);
  18. </script>

This works because {{each …}} and ${ … } are jQuery.tmpl syntaxes. What’s more, it’s trivial to nest templates: because you can use data-bind attributes from inside a template, you can simply put a data-bind="template: …" inside a template to render a nested one.

Please note that, as of December 2011, jQuery.tmpl is no longer under active development. In due course, it will be succeded by JsRender, which is currently not yet in beta.

Note 6: Using the Underscore.js template engine

The Underscore.js template engine by default uses ERB-style delimiters (<%= … %>). Here’s how the preceding example’s template might look with Underscore:

  1. <script type="text/html" id="peopleList">
  2. <% _.each(people(), function(person) { %>
  3. <li>
  4. <b><%= person.name %></b> is <%= person.age %> years old
  5. </li>
  6. <% }) %>
  7. </script>

Here’s a simple implementation of integrating Underscore templates with Knockout. The integration code is just 16 lines long, but it’s enough to support Knockout data-bind attributes (and hence nested templates) and Knockout binding context variables ($parent, $root, etc.) too.

If you’re not a fan of the <%= … %> delimiters, you can configure the Underscore template engine to use any other delimiter characters of your choice.

Dependencies

  • Native templating does not require any library other than Knockout itself
  • String-based templating works only once you’ve referenced a suitable template engine, such as jQuery.tmpl or the Underscore template engine.

(c) knockoutjs.com