KnockoutJS - 组件


组件是组织 UI 代码的一种重要方式,可以构建大型应用程序并提高代码的可重用性。

它是从其他组件继承或嵌套的。对于加载和配置,它定义了自己的约定或逻辑。

它被打包以便在整个应用程序或项目中重复使用。代表应用程序或小控件/小部件的完整部分。它可以按需加载或预加载。

组件注册

组件可以使用ko.components.register() API 进行注册。它有助于在 KO 中加载和表示组件。注册时需要带有配置的组件名称。配置指定如何确定 viewModel 和模板。

句法

组件可以注册如下 -

ko.components.register('component-name', {
   viewModel: {...},    //function code
   template: {....)	//function code
});
  • 组件名称可以是任何非空字符串。

  • viewModel是可选的,可以采用下一节中列出的任何 viewModel 格式。

  • template是必需的,并且可以采用下一节中列出的任何模板格式。

声明一个 ViewModel

下表列出了可用于注册组件的 viewModel 格式。

先生。 viewModel 表格和描述
1

构造函数

它为每个组件创建一个单独的 viewModel 对象。对象或函数用于在组件视图中绑定。

function SomeComponentViewModel(params) {
   this.someProperty = params.something;
}
ko.components.register('component name', {
   viewModel: SomeComponentViewModel,
   template: ...
});
2

共享对象实例

viewModel 对象实例是共享的。传递实例属性以直接使用该对象。

var sharedViewModelInstance = { ... };

ko.components.register('component name', {
   viewModel: { instance: sharedViewModelInstance },
   template: ...
});
3

创建视图模型

它调用一个充当工厂的函数,并且可以用作可以返回对象的视图模型。

ko.components.register('component name', {  
   viewModel: {  
      createViewModel: function (params, componentInfo) {  
         ...       //function code  
         ...
      }  
   },  
   template: ....  
});
4

AMD模块

它是一种用于定义模块的模块格式,其中模块和依赖项都是异步加载的。

ko.components.register('component name', {
   viewModel: { require: 'some/module/name' },
   template: ...
});

define(['knockout'], function(ko) {
   function MyViewModel() {
      // ...
   }

   return MyViewModel;
});

陈述一个模板

下表列出了可用于注册组件的模板格式。

先生。 模板表格
1

元素编号

ko.components.register('component name', {
   template: { element: 'component-template' },
   viewModel: ...
});
2

元素实例

var elemInstance = document.getElementById('component-template');

ko.components.register('component name', {
   template: { element: elemInstance },
   viewModel: ...
});
3

标记字符串

ko.components.register('component name', {
   template: '<input data-bind = "value: yourName" />\
      <button data-bind = "click: addEmp">Add Emp </button>',
   viewModel: ...
});
4

DOM 节点

var emp = [
   document.getElementById('node 1'),
   document.getElementById('node 2'),
];

ko.components.register('component name', {
   template: emp,
   viewModel: ...
});
5

文档碎片

ko.components.register('component name', {
   template: someDocumentFragmentInstance,
   viewModel: ...
});
6

AMD模块

ko.components.register('component name', {
   template: { require: 'some/template' },
   viewModel: ...
});

组件注册为单个 AMD 模块

AMD 模块可以自行注册组件,而无需使用 viewModel/模板对。

ko.components.register('component name',{ require: 'some/module'});

组件绑定

组件绑定有两种方式。

  • 完整语法- 它将参数和对象传递给组件。它可以通过使用以下属性。

    • name - 它添加组件名称。

    • params - 它可以在组件上的对象中传递多个参数。

<div data-bind='component: {
   name: "tutorials point",
   params: { mode: "detailed-list", items: productsList }
}'>
</div>
  • 速记语法- 它将字符串作为组件名称传递,并且其中不包含参数。

<div data-bind = 'component: "component name"'></div>
  • 仅模板组件- 组件只能定义模板而不指定视图模型。

ko.components.register('component name', {
   template:'<input data-bind = "value: someName" />,
});
  • 在没有容器元素的情况下使用组件- 可以在不使用额外容器元素的情况下使用组件。这可以使用与注释标签类似的无容器流控制来完成。

<!--ko.component: ""-->
<!--/ko-->

自定义元素

Custom element is a way for rendering a component. Here, you can directly write a selfdescriptive markup element name instead of defining a placeholder, where the components are binded through it.

<products-list params = "name: userName, type: userType"></products-list>

Passing Parameter

params attribute is used to pass the parameter to component viewModel. It is similar to data-bind attribute. The contents of the params attribute are interpreted like a JavaScript object literal (just like a data-bind attribute), so you can pass arbitrary values of any type. It can pass the parameter in following ways −

  • Communication between parent and child components − The component is not instantiated by itself so the viewmodel properties are referred from outside of the component and thus would be received by child component viewmodel. For example, you can see in the following syntax that ModelValue is the parent viewmodel, which is received by child viewModel constructor ModelProperty.

  • Passing observable expressions − It has three values in params parameter.

    • simpleExpression − It is a numeric value. It does not involve any observables.

    • simpleObservable − It is an instance that is defined on parent viewModel. The parent viewModel will automatically get the changes on observable done by child viewModel.

    • observableExpression − Expression reads the observable when the expression is evaluated by itself. When the observable value changes, then the result of expression can also changs over time.

We can pass the parameters as follows −

<some-component
   params = 'simpleExpression: 1 + 1,
      simpleObservable: myObservable,
      observableExpression: myObservable() + 1'>
</some-component>

We can pass the parameters in viewModel as follows −

<some-component
   params = 'objectValue:{a: 3, b: 2},
      dateValue: new date(),
      stringValue: "Hi",
      numericValue:123,
      boolValue: true/false,
      ModelProperty: ModelValue'>
</some-component>

Passing Markup into Components

The received markup is used to create a component and is selected as a part of the output. Following nodes are passed as part of the output in the component template.

template: { nodes: $componentTemplateNodes }

Controlling custom element tag names

The names which you register in the components using ko.components.register, the same name corresponds to the custom element tag names. We can change the custom element tag names by overriding it to control using getComponentNameForNode.

ko.components.getComponentNameForNode = function(node) {
   ...
   ...   //function code
   ...
}

Registering Custom Elements

The custom elements can be made available immediately, if the default component loader is used and hence the component is registered using ko.components.register. If we are not using the ko.components.register and implementing the custom component loader, then the custom element can be used by defining any element name of choice. There is no need to specify configuration when you are using ko.components.register as the custom component loader does not use it anymore.

ko.components.register('custom-element', { ......... });

Example

<!DOCTYPE html>
   <head>
      <title>KnockoutJS Components</title>
      <script src = "https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
      <script src = "https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"></script>
   </head>
   
   <body>
      <!--params attribute is used to pass the parameter to component viewModel.-->
      <click params = "a: a, b: b"></click>

      <!--template is used for a component by specifying its ID -->
      <template id = "click-l">
         <div data-bind = "text: a"></div>

         <!--Use data-bind attribute to bind click:function() to ViewModel. -->
         <button data-bind = "click:function(){callback(1)}">Increase</button>
         <button data-bind = "click:function(){callback(-1)}">Decrease</button>
      </template>

      <script>
         //Here components are registered
         ko.components.register('click', {
            
            viewModel: function(params) {
               self = this;
               this.a = params.a;
               this.b = params.b;

               this.callback = function(num) {
                  self.b(parseInt(num));
                  self.a( self.a() + parseInt(num) );
               };
            },
            template: { element: 'click-l' }
         });

         //keeps an eye on variable for any modification in data
         function viewModel() {
            this.a = ko.observable(2);
            this.b = ko.observable(0);
         }

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

Output

Let's carry out the following steps to see how the above code works −

  • Save the above code in component_register.htm file.

  • Open this HTML file in a browser.

组件加载器

组件加载器用于异步传递给定组件名称的模板/视图模型对。

默认组件加载器

默认组件加载器取决于显式注册的配置。每个组件在使用该组件之前都会被注册。

ko.components.defaultLoader

组件加载器实用函数

默认组件加载器可以使用以下函数进行读写。

先生。 实用功能及说明
1

ko.components.register(名称,配置)

组件已注册。

2

ko.components.isRegistered(名称)

如果特定组件名称已注册,则返回 true,否则返回 false。

3

ko.components.unregister(名称)

组件名称将从注册表中删除。

4

ko.components.get(名称, 回调)

该函数依次向每个注册的加载器查找谁首先传递了组件名称的 viewModel/模板定义。然后它通过调用回调返回 viewModel/template 声明。如果注册的加载程序找不到有关该组件的任何信息,则会调用callback(null)

5

ko.components.clearCachedDefinition(名称)

当我们想要清除给定的组件缓存条目时可以调用此函数。如果下次需要该组件,将再次咨询加载程序。

实现自定义组件加载器

自定义组件加载器可以通过以下方式实现 -

  • getConfig(name,callback) - 根据名称,我们可以以编程方式传递配置。我们可以调用callback(componentConfig)来传递配置,其中objectconfig对象可以被loadComponent或任何其他加载器使用。

  • loadComponent(name, componentConfig, callback) - 此函数根据配置方式解析 viewModel 和配置的模板部分。我们可以调用回调(结果)来传递视图模型/模板对,其中对象结果由以下属性定义。

    • 模板- 必需。返回 DOM 节点数组。

    • createViewModel(params, componentInfo) - 可选。根据 viewModel 属性的配置方式返回 viewModel 对象。

  • loadTemplate(name, templateConfig, callback) - DOM 节点使用自定义逻辑在模板中传递。对象 templateConfig 是来自对象 componentConfig 的模板的属性。调用callback(domNodeArray)来传递DOM节点数组。

  • loadViewModel(name, templateConfig, callback) - viewModel 工厂使用自定义逻辑在 viewModel 配置中传递。