KnockoutJS 3.X API 第四章(13) template绑定

目的

template绑定(模板绑定)使用渲染模板的结果填充关联的DOM元素。 模板是一种简单方便的方式来构建复杂的UI结构 。

下面介绍两种使用模板绑定的方法:

  • 本地模板是支持foreach,if,with和其他控制流绑定的机制。 在内部,这些控制流绑定捕获元素中包含的HTML标记,并将其用作模板以针对任意数据项进行呈现。 此功能内置在Knockout中,不需要任何外部库。
  • 基于字符串的模板是一种将Knockout连接到第三方模板引擎的方法。 Knockout会将您的模型值传递给外部模板引擎,并将生成的标记字符串注入到文档中。 请参阅下面的备注6使用jquery.tmpl和Underscore模板引擎的示例。

    参数

  • 快速语法:如果你只是提供一个字符串值,KO会将其解释为要渲染的模板的ID。它提供给模板的数据将是您当前的模型对象。

  • 要获得更多控件,请传递具有以下属性的某些组合的JavaScript对象:

  • name — 包含要渲染的模板的元素的ID - 有关如何以编程方式更改此设置,请参见备注5。
  • nodes —直接传递DOM节点数组以用作模板。这应该是一个不可观察的数组,并注意元素将从他们当前的父(如果他们有一个)中删除。如果您还为name传递了一个非空值,则忽略此选项。
  • data — 要提供为要呈现的模板的数据的对象。如果省略此参数,KO将查找foreach参数,或者使用当前模型对象返回。
  • if — 如果提供此参数,那么只有在指定的表达式求值为true(或true-ish值)时,才会呈现模板。这可以有助于防止null observable在填充之前与模板绑定。
  • foreach — 指示KO以“foreach”模式渲染模板 - 有关详细信息,请参见备注2。
  • as — 当与foreach结合使用时,为正在呈现的每个项目定义别名 - 有关详细信息,请参见备注3。
  • afterRender, afterAddbeforeRemove — 要针对呈现的DOM元素调用的回调函数 - 请参阅备注4

    备注1:渲染命名模板

    通常,当您使用控制流绑定(foreach,with,if等)时,不需要给您的模板命名:它们是由DOM元素内的标记隐式和匿名定义的。 但是如果你想要,你可以将模板分解成一个单独的元素,然后通过名称引用它们:

    Participants

    Here are the participants:

    源码:

    <h2>Participants</h2>
    Here are the participants:
    <div data-bind="template: { name: 'person-template', data: buyer }"></div>
    <div data-bind="template: { name: 'person-template', data: seller }"></div>
     
    <script type="text/html" id="person-template">
        <h3 data-bind="text: name"></h3>
        <p>Credits: <span data-bind="text: credits"></span></p>
    </script>
     
    <script type="text/javascript">
         function MyViewModel() {
             this.buyer = { name: 'Franklin', credits: 250 };
             this.seller = { name: 'Mario', credits: 5800 };
         }
         ko.applyBindings(new MyViewModel());
    </script>

    在此示例中,'person-template'标记使用两次:一次用于买方,一次用于卖方。 请注意,模板标记被包装在<script type =“text / html”>中 - 必须使用虚拟类型属性,以确保标记不会作为JavaScript执行,Knockout不会尝试对该标记应用绑定,除非 它被用作模板。

    使用命名模板不是经常被用到,但有时它可以帮助减少重复的标记。

    备注2:对命名模板使用“foreach”选项

    Participants

    Here are the participants:

    源码:

    <h2>Participants</h2>
    Here are the participants:
    <div data-bind="template: { name: 'person-template', foreach: people }"></div>
     
    <script type="text/html" id="person-template">
        <h3 data-bind="text: name"></h3>
        <p>Credits: <span data-bind="text: credits"></span></p>
    </script>
     <script>
     function MyViewModel() {
         this.people = [
             { name: 'Franklin', credits: 250 },
             { name: 'Mario', credits: 5800 }
         ]
     }
     ko.applyBindings(new MyViewModel());
    </script>

    这给出了与在您使用foreach的元素内直接嵌入匿名模板相同的结果,例如:

    <div data-bind="foreach: people">
        <h3 data-bind="text: name"></h3>
        <p>Credits: <span data-bind="text: credits"></span></p>
    </div>

    备注3:使用“as”给“foreach”项目一个别名

    当嵌套foreach模板时,引用层次结构中较高级别的项目通常很有用。 一种方法是在绑定中引用$ parent或其他绑定上下文变量。

    然而,一个更简单和更优雅的选项是使用as来为你的迭代变量声明一个名字。 例如:

    <ul data-bind="template: { name: 'employeeTemplate',
                                      foreach: employees,
                                      as: 'employee' }"></ul>

    注意与as相关联的字符串值“employee”。 现在在这个foreach循环中的任何地方,你的子模板中的绑定将能够引用employee来访问正在呈现的employee对象。

    如果你有多个嵌套的foreach块,这是非常有用的,因为它给你一个明确的方法来引用层次结构中更高级别上声明的任何命名项。 这是一个完整的例子,显示季节可以在渲染一个月时被引用:

      源码:

      <ul data-bind="template: { name: 'seasonTemplate', foreach: seasons, as: 'season' }"></ul>
       
      <script type="text/html" id="seasonTemplate">
          <li>
              <strong data-bind="text: name"></strong>
              <ul data-bind="template: { name: 'monthTemplate', foreach: months, as: 'month' }"></ul>
          </li>
      </script>
       
      <script type="text/html" id="monthTemplate">
          <li>
              <span data-bind="text: month"></span>
              is in
              <span data-bind="text: season.name"></span>
          </li>
      </script>
       
      <script>
          var viewModel = {
              seasons: ko.observableArray([
                  { name: 'Spring', months: [ 'March', 'April', 'May' ] },
                  { name: 'Summer', months: [ 'June', 'July', 'August' ] },
                  { name: 'Autumn', months: [ 'September', 'October', 'November' ] },
                  { name: 'Winter', months: [ 'December', 'January', 'February' ] }
              ])
          };
          ko.applyBindings(viewModel);
      </script>

      提示:请记住将字符串字面值传递为as(例如,as:'season',而不是as:season),因为您要出给一个新变量命名,而不是读取已经存在的变量的值。

      备注4:使用afterRender, afterAdd,  beforeRemove

      有时,您可能希望对由模板生成的DOM元素运行自定义后处理逻辑。 例如,如果您使用JavaScript窗口部件库(如jQuery UI),则可能需要拦截模板的输出,以便可以对其运行jQuery UI命令,将一些渲染的元素转换为日期选择器,滑块或别的什么东西。

      通常,对DOM元素执行此类后处理的最佳方法是编写自定义绑定,但如果您只想访问模板发出的原始DOM元素,则可以使用afterRender。

      传递函数引用(函数文字,或给出视图模型上的函数名称),Knockout将在渲染或重新渲染模板后立即调用它。 如果你使用foreach,Knockout将为添加到你的observable数组的每个项目调用你的afterRender回调函数。 例如,

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

      并在视图模型(即包含myData的对象)上定义相应的函数:

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

      如果您正在使用foreach,并且只希望通知有关特定要添加或正在删除的元素,则可以使用afterAdd和beforeRemove。 有关详细信息,请参阅第四章foreach绑定的文档

      备注5:动态选择使用哪个模板

      如果有多个命名模板,则可以为名称选项传递observable。 随着observable的值被更新,元素的内容将使用适当的模板重新渲染。 或者,您可以传递回调函数来确定要使用哪个模板。 如果您使用的是foreach模板模式,Knockout将评估数组中每个项目的函数,并将该项目的值作为唯一的参数。 否则,函数将给出数据选项的值,或者返回提供整个当前模型对象。

      源码:

      <ul data-bind='template: { name: displayMode,
                                 foreach: employees }'> </ul>
       
      <script>
          var viewModel = {
              employees: ko.observableArray([
                  { name: "Kari", active: ko.observable(true) },
                  { name: "Brynn", active: ko.observable(false) },
                  { name: "Nora", active: ko.observable(false) }
              ]),
              displayMode: function(employee) {
                  // Initially "Kari" uses the "active" template, while the others use "inactive"
                  return employee.active() ? "active" : "inactive";
              }
          };
       
          // ... then later ...
          viewModel.employees()[1].active(true); // Now "Brynn" is also rendered using the "active" template.
      </script>

      如果你的函数引用了observable值,那么当这些值发生变化时,绑定就会更新。 这将导致使用适当的模板重新呈现数据。

      如果你的函数包含第二个参数,那么它将接收整个绑定上下文。 然后,当动态选择模板时,可以访问$ parent或任何其他绑定上下文变量。 例如,您可以修改上述代码段,如下所示:

      displayMode: function(employee, bindingContext) {
          // Now return a template name string based on properties of employee or bindingContext
      }

      备注6:使用jQuery.tmpl,一个外部的基于字符串的模板引擎

      在绝大多数情况下,Knockout的本地模板和foreach,if,with和其他控制流绑定将需要构建一个任意复杂的UI。 但是,如果您希望与外部模板库(例如Underscore模板引擎或jquery.tmpl)集成,Knockout提供了一种方法。

      默认情况下,Knockout支持jquery.tmpl。 要使用它,您需要按以下顺序引用以下库:

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

      然后,您可以在模板中使用jQuery.tmpl语法。 例如

      <h1>People</h1>
      <div data-bind="template: 'peopleList'"></div>
       
      <script type="text/html" id="peopleList">
          {{each people}}
              <p>
                  <b>${name}</b> is ${age} years old
              </p>
          {{/each}}
      </script>
       
      <script type="text/javascript">
          var viewModel = {
              people: ko.observableArray([
                  { name: 'Rod', age: 123 },
                  { name: 'Jane', age: 125 },
              ])
          }
          ko.applyBindings(viewModel);
      </script>

      这是因为{{each ...}}和$ {...}是jQuery.tmpl语法。 更重要的是,嵌套模板很简单:因为您可以在模板中使用数据绑定属性,您可以简单地在模板中放置一个data-bind =“template:...”来渲染嵌套的模板。

      请注意,截至2011年12月,jQuery.tmpl已不再处于积极开发阶段。 我们建议使用Knockout的本地基于DOM的模板(即foreach,if,with等绑定),而不是jQuery.tmpl或任何其他基于字符串的模板引擎。

    • 原文地址:https://www.cnblogs.com/smallprogram/p/5953479.html