KnockoutJS - 组件绑定



此绑定用于将组件插入 DOM 元素并可选地传递参数。此绑定可以通过以下两种方式实现:

  • 简写语法
  • 完整语法

简写语法

在这种方法中,只指定组件名称,而不指定任何参数。

语法

<div data-bind = 'component: "component-name"'></div>

传递的参数值可以是可观察对象。因此,每当可观察对象发生变化时,旧的组件实例将被销毁,并根据更新后的参数值创建新的组件实例。

完整语法

此方法以对象的格式接受参数。

语法

<div data-bind = 'component: {
   name: "component-name",
   params: { param1: value1, param2:value2 ...}
}'></div>

该对象由以下两个项目组成:

  • name - 这是要插入的组件的名称。如前所述,这可以是可观察对象。

  • params - 这是要传递给组件的对象。大多数情况下,这将是一个包含多个参数的键值对对象。这通常由 ViewModel 的构造函数接收。

组件处理流程

下图说明了通过组件绑定注入组件时发生的流程。

component lifecycle

让我们详细了解一下这个过程:

从组件加载器接收 ViewModel 工厂和模板 - 默认加载器请求并接收已注册的 ViewModel 和模板。默认情况下,这是一个异步过程。

克隆组件模板 - 在此步骤中,克隆组件模板并将其插入 DOM 元素。如果存在任何现有内容,则将其删除。

如果存在,则实例化 ViewModel - 在此步骤中,实例化 ViewModel。如果 ViewModel 以构造函数的形式提供,则 KO 调用。

new ViewModelName(params)

如果 ViewModel 以工厂函数格式提供,即 createViewModel,则 KO 调用。

createViewModel(params, yourcomponentInfo)

此处 yourcomponentInfo.element 是插入模板的元素。

将 ViewModel 绑定到视图 - 在此阶段,ViewModel 绑定到视图。如果未提供 ViewModel,则使用组件绑定中提到的参数进行绑定。

组件现在已准备就绪 - 在此阶段,组件已准备就绪并可以正常工作。组件会监控任何可观察的参数,以便写入更改的值。

如果组件丢失,则销毁 ViewModel - 如果组件绑定的名称值发生可观察的变化,或者某些控制流绑定删除了旨在容纳组件输出的 DOM 元素容器本身,则会调用 ViewModel 的销毁函数。销毁发生在任何元素容器从 DOM 中移除之前。

示例

让我们来看一个演示组件绑定用法的示例。

<!DOCTYPE html>
   <head>
      <title>KnockoutJS Component binding</title>
      <script src = "https://ajax.aspnetcdn.com/ajax/knockout/knockout-3.3.0.js"
         type = "text/javascript"></script>
   </head>
   
   <body>
      <h4>Component binding without parameters</h4>
      <div data-bind = 'component: "calculate-sum"'></div>

      <h4>Component binding passing parameters</h4>
      <div data-bind = 'component: {
         name: "calculate-sum",
         params: { number1: 2, number2: 3 }
      }'></div>

      <script>
         ko.components.register('calculate-sum', {
            
            viewModel: function(params) {
               this.number1 = ko.observable(params && params.number1);
               this.number2 = ko.observable(params && params.number2);

               this.result = ko.computed(function() {
                  var sum = Number(this.number1()) + Number(this.number2());
                  if ( isNaN(sum) )
                  sum = 0;
                  return sum;
               },this);
            },
            
            template: 'Enter Number One: <input data-bind = "value: number1" /> <br> <br>'+
               ' Enter Number Two: <input data-bind = "value: number2" /> <br> <br>'+
               ' Sum  = <span data-bind = "text: result" />'
         });

         ko.applyBindings();
      </script>
      
   </body>
</html>

输出

让我们执行以下步骤来查看上述代码的工作原理:

  • 将上述代码保存在 **component-bind.htm** 文件中。

  • 在浏览器中打开此 HTML 文件。

  • 在两个文本框中输入数字,并观察总和是如何计算的。

观察结果

仅包含模板的组件

可以创建没有 ViewModel 的组件。组件可以只包含如下所示的模板。

ko.components.register('my-component', {
   template: '<div data-bind = "text: productName"></div>'
});

DOM 将如下所示:

<div data-bind = 'component: {
   name: "my-component",
   params: { productName: someProduct.name }
}'></div>

在没有 DOM 容器元素的情况下使用组件绑定

可能存在无法将组件插入 DOM 元素的情况。仍然可以借助基于如下所示注释标签的无容器语法执行必要的绑定。

<!--ko--> 和 <!--/ko--> 充当起始和结束标记,使其成为虚拟语法,并像真实的容器一样绑定数据。

内存管理和销毁

可以可选地将销毁函数作为 ViewModel 的一部分添加。如果包含此函数,则每当组件丢失或容器元素本身被移除时,它都会被调用。最好使用销毁函数来释放不需要的对象占用的资源,这些资源默认情况下不能被垃圾回收。以下是一些示例:

  • setInterval 方法将一直运行,直到明确清除。clearInterval (handle) 用于停止此过程。

  • 需要明确销毁 ko.computed 属性。否则,它们可能仍然会继续接收来自其底层可观察对象的通知。可以使用纯计算函数避免手动销毁。

  • 确保在订阅上使用 dispose() 方法,否则它会一直触发更改直到销毁。

  • 需要销毁在 DOM 元素上创建并在 createViewModel 内部创建的自定义事件处理程序。

knockoutjs_declarative_bindings.htm
广告