在应用程序中使用KnockoutJS框架

概述

本文演示了如何使用“Knockout.js”,这是一个第三方的JavaScript库,它可以使用干净的底层数据模型创建丰富的,反应迅速的显示和编辑器用户界面。 如果有用户界面的任何部分需要动态更新(例如,根据用户的操作变化了或当外部数据源变化了),knockout库可以帮助我们更简单地,可维护地实现它。 我们可以在这里到相关文档和源。

它的一些主要特点是:

  • 较好的依赖性跟踪 - 当您的数据模型发生改变时,自动更新你的UI中的相应部分。
  • 声明式绑定 - 使用一个简单而明显的方法将你的UI中的某些部分连接到你的数据模型中。 你可以很容易地使用任意嵌套绑定的上下文构造一个复杂的动态的用户界面。
  • 简单的扩展 - 实现自定义行为,并作为新的声明绑定,便于在代码中重复使用。

对于网站和Web应用程序,KnockoutJS遵循模型 - 视图 - 视图模型(MVVM)的开发风格。 MVVM是一种开发风格,为了便于测试,设计不同的对象类时,将用户界面逻辑从业务功能中独立出来了。

  • MVVM风格应用程序的第一个原则是确定业务模式。 模是一个对象,它通常最直接地代表了你工作的业务系统中一个真实世界(real-world)的对象。 它包含一些属性和函数,比如业务名称和反应。
  • MVVM风格应用程序的第二个原则是视图(View)。 视图是HTML标识,它描述了布局,元素(按钮,文本框),颜色和用户界面上其他可视部分。 它没有嵌入式的逻辑或代码,它是完全陈述。
  • MVVM风格应用程序的第三个原则是视图模型。 该视图模型提供了视图和模型之间的连接。
  • MVVM的最终原则是绑定的概念。 绑定的概念是将属性和用户界面元素(如HTML元素)连接到一个对象的功能和属性上,例如一个视图模型(ViewModel)。 绑定往往在视图标识中声明。

KnockoutJS应用程序

此应用程序展示了编辑一个嵌套数据结构的方法,来添加,删除联系人,并将其保存为JSON格式。

应用程序的视图部分

添加下面一行,即使用<script> 标签来引用JavaScript文件。

<script type="text/javascript" src="./js/knockout-3.0.0.debug.js"></script>

“View”包含一个表和一些按钮,表中的输入区域用于输入联系方式,按钮用来删除每个联系人和电话号码。 表外还有两个按钮用来添加多个联系人,并将它们保存到JSON格式,然后将其贴在底部的文本区中。

<table class='contactsEditor' align="center">
  <tr>
    <th>First name</th>
    <th>Last name</th>
    <th>Phone numbers</th>
  </tr>
  <tbody data-bind="foreach: contacts">
    <tr>
      <td class="contactsEditor1" align="center" valign="bottom">
        <input data-bind='value: firstName' size="7" class="input" /> 
        <a data-role="button" data-inline="true" href='#' data-bind='click: $root.removeContact' data-icon="delete"></a>
      </td>
      <td class="contactsEditor1" align="center">
        <input data-bind='value: lastName' size="7" class="input" />
      </td>
      <td class="contactsEditor1">
        <table>
	  <tbody data-bind="foreach: phones">
	    <tr>
		<td align="center"><input data-bind='value: number' size="8" class="input" /></td>
		<td align="center">
                  <a data-bind='click: $root.removePhone' data-role="button" data-inline="true" data-icon="delete"></a>
                </td>
	    </tr>
	  </tbody>
	</table>
        <center>
          <a href='#' data-role="button" data-inline="true" data-bind='click: $root.addPhone'>Add number</a>
        </center>
      </td>
    </tr>
  </tbody>
</table>
<center>
  <button data-bind='click: addContact' data-inline="true">Add a contact</button>
  <button data-bind='click: save, enable: contacts().length > 0' data-inline="true">Save to JSON</button>
  <textarea data-bind='value: lastSavedJson' rows='15' cols='60'> </textarea>
</center>

上面的代码中,“data-bind”告诉Knockout如何声明将视图模型的属性与DOM元素联系在一起。

  • foreach绑定用于将JavaScript联系人数组转变为一个TABLE。 每当联系人数组发生变化时,用户界面​​也会相应地变化,从而没有必要去指出如何注入新的 <tr> 或者注在哪里注入他们。 用户界面的其他部分保持同步。
  • value绑定,和一些普通的HTML <input>控件一起,使数据可编辑。
  • click绑定用于将click和添加的视图模型关联在一起。
  • enable绑定根据给定的条件启用或禁用按钮。

应用程序中的视图模型

Knockout有可观察概念 - 这些是一些属性,每当输入字段的值变化了,它们便会自动发出通知。 所有的联系人姓名,号码保留在数组中。 现在使用“ko.observableArray”绑定“View”,使其能够检测用户做出的对数组的任改动,并做出反应。 这是在许多情况下是有用的,显示或编辑多个值时,需要用户界面中重复的部分重复出现和消失,就像条目的添加和移除一样。

var initialData = [
	             { firstName: "Danny", lastName: "LaRusso", phones: [
	                                                                    { number: "9160876557" },
	                                                                    { number: "9989779179"}]
	             },
	             { firstName: "Sensei", lastName: "Miyagi", phones: [
	                                                                    { number: "9959392729" },
	                                                                    { number: "8985627183"}]
	             }
	          ];

var ContactsModel = function(contacts) {
		var self = this;
		self.contacts = ko.observableArray(ko.utils.arrayMap(contacts, function(contact) {
			return { firstName: contact.firstName, lastName: contact.lastName, phones:   ko.observableArray(contact.phones) };
}));

self.addContact = function() {
	    self.contacts.push({
			firstName: "",
			lastName: "",
			phones: ko.observableArray()
	    });
};

self.removeContact = function(contact) {
	    self.contacts.remove(contact);
};

self.addPhone = function(contact) {
	    contact.phones.push({
		       number: ""
	    });
};

self.removePhone = function(phone) {
	    $.each(self.contacts(), function() { this.phones.remove(phone) })
};

self.save = function() {
	    self.lastSavedJson(JSON.stringify(ko.toJS(self.contacts), null, 2));
            var string=JSON.stringify(ko.toJS(self.contacts), null, 2);
            console.log(string);
	    tizen.filesystem.resolve(
				'documents', 
				function(dir){
					documentsDir = dir;
					dir.listFiles(onSuccessFilesList,onerrorFiles);
				}, function(e){
					console.log("Error" + e.message);
				}, "rw"
	    );
	    function onSuccessFilesList(files) {
				var fileName = "Contacts"+ (files.length + 1)+".json";
				var testFile = documentsDir.createFile(fileName);

				if (testFile != null) {
					testFile.openStream( "w",
						function(fs){ 
							fs.write(string);
							fs.close();
							alert("Contacts are saved to "+fileName+" inside Documents folder");
							}, function(e){
								console.log("Error " + e.message);
							}, "UTF-8"
					);
				}
			}

	    function onerrorFiles( err){
				console.log("--------Error"+ err );
	    }
	};
            self.lastSavedJson = ko.observable("")
};

ko.applyBindings(new ContactsModel(initialData));

addContact, removeContact, addPhone, removePhone, save, lastSavedJson是绑定到用户界面的函数。

每次点击“Add Number”按钮,都会触发视图模型中的addPhone(),它改变视图模型的状态,从而引发用户界面更新。 其他函数按照类似的方式运行。 创建的JSON数据被绑定到了文本区域,并粘贴到文本区中,最后文件系统API保存到"Documents"文件夹中的一个文件中。 由于data-bind属性不是HTML原生的,浏览器不知道它表示什么,所以Knockout用来激活它,使之生效。 “ko.applyBindings”用于激活knockoutJS。 它使用视图模型对象作为参数,该参数和declarative绑定一起使用,并激活它。

屏幕截图

文件附件: