Knockoutjs 的Components 是一种自定义的组件,它以一种强大、简介的方式将你自己的ui代码组织成一种单独的、可重用的模块,自定义的组件(Component)有以下特点:
1.可以替代单独的widgit或者控制逻辑,或者你自己application的整个模块;
2.包含自己的view,通常也包含了自己的viewModel(这个viewModel也可以不进行定义)
3.可以预加载,可以通过AMD或者其他模块系统的方式根据需要异步加载
4.可以接收参数,根据需要选择性的对这些参数进行修改并返回,或者调用回调函数
5.组件可以进行组合,或者从别的组件进行继承
6.能够进行打包,跨项目复用
7.允许你定义自己的逻辑来进行js文件的配置和加载
这种模式对大型应用来讲是非常有利的,因为这种自定义组件的模式,通过清晰的组织和封装简化了开发复杂度,通过根据需要增量式的加载你自己的应用代码和模板大大提高了运行时的性能。
自定义元素:是一种使用自定义组件的非常便利的方式。你不必一定要用一对<div data-bind=""></div>套在你需要绑定的标签的外层来进行数据的绑定,而是用你自己描述的标记语言,比如<voting-button><product-editor>,这种形式,标签里的是你自定义的元素名称。Knockout在这一点上也兼容老版本的浏览器,IE6兼容。
例子一:一个 like/dislike的小插件
首先,你需要用来
ko.components.register注册一个component。一个组件的定义需要有一个viewModel和一个template:
ko.components.register('like-widget', { viewModel: function(params) { // Data: value is either null, 'like', or 'dislike' this.chosenValue = params.value; // Behaviors this.like = function() { this.chosenValue('like'); }.bind(this); this.dislike = function() { this.chosenValue('dislike'); }.bind(this); }, template: '<div class="like-or-dislike" data-bind="visible: !chosenValue()">\ <button data-bind="click: like">Like it</button>\ <button data-bind="click: dislike">Dislike it</button>\ </div>\ <div class="result" data-bind="visible: chosenValue">\ You <strong data-bind="text: chosenValue"></strong> it\ </div>' });通常情况下,你需要引入外部文件来加载viewModel和模板,而不是像上面这样写到同一个文件里。稍后我们讲解怎么以引入外部文件的方式加载viewModel和template。
现在,通过进行组件绑定(component binding)或者自定义元素的方式在你的view(通常是html文档)里使用上面的自定义组件了。
viewCode:
<ul data-bind="foreach: products"> <li class="product"> <strong data-bind="text: name"></strong> <like-widget params="value: userRating"></like-widget> </li> </ul>
function Product(name, rating) { this.name = name; this.userRating = ko.observable(rating || null); } function MyViewModel() { this.products = [ new Product('Garlic bread'), new Product('Pain au chocolat'), new Product('Seagull spaghetti', 'like') // This one was already 'liked' ]; } ko.applyBindings(new MyViewModel());
在这个例子里面,组件通过Product的viewModel中的可监控属性:userRating来进行显示、编辑。
例子二:从外部文件加载like/dislike组件
在大多数的应用中,一般都会将组件的viewModel和模板放在外部文件中,如果你使用require.js这样的模块加载器来配置加载knockout来获取外部ADM模块的话,那么就可以通过bundle/minified的方式来进行预加载,或者按需增量加载。
下面是一个使用require.js的配置示例:
ko.components.register('like-or-dislike', { viewModel: { require: 'files/component-like-widget' }, template: { require: 'text!files/component-like-widget.html' } });需要的文件:
为了实现改组件(component)的功能,需要文件
files/component-like-widget.js code:
files/component-like-widget.js
和
files/component-like-widget.html
。你是不是发现,这比直接在组件的定义里面包含viewModel和template要整洁、方便很多。
files/component-like-widget.js code:
define(['knockout'], function(ko) { function LikeWidgetViewModel(params) { this.chosenValue = params.value; } LikeWidgetViewModel.prototype.like = function() { this.chosenValue('like'); }; LikeWidgetViewModel.prototype.dislike = function() { this.chosenValue('dislike'); }; return LikeWidgetViewModel; });files/component-like-widget.html code:
<div class="like-or-dislike" data-bind="visible: !chosenValue()"> <button data-bind="click: like">Like it</button> <button data-bind="click: dislike">Dislike it</button> </div> <div class="result" data-bind="visible: chosenValue"> You <strong data-bind="text: chosenValue"></strong> it. And this was loaded from an external file. </div>
下面是源码:
view :
<ul data-bind="foreach: products"> <li class="product"> <strong data-bind="text: name"></strong> <like-or-dislike params="value: userRating"></like-or-dislike> </li> </ul> <button data-bind="click: addProduct">Add a product</button>
viewModel:
function Product(name, rating) { this.name = name; this.userRating = ko.observable(rating || null); } function MyViewModel() { this.products = ko.observableArray(); // Start empty } MyViewModel.prototype.addProduct = function() { var name = 'Product ' + (this.products().length + 1); this.products.push(new Product(name)); }; ko.applyBindings(new MyViewModel());
在你第一次点击“Add product” 按钮之前,打开浏览器的开发工具Network,你会发现组件的.js/.html文件第一次是按需加载的,加载之后就一直存在以备下次复用。
Knockoutjs源出处:http://knockoutjs.com/documentation/component-overview.html