本片为Anguar2学习笔记的第二篇文章,将会讲述Angular2的数据绑定功能(仅涉及单向),ngFor、ngIf指令的使用以及如果分离MVVM。
本片内容参照官方文档DisplayingData。
工程演示
这次我们来建立一个新的工程DisplayData。
本篇笔记结束后,目录结构应该是这个样子,你不需要提前创建这个目录结构,在需要的时候我会说明。
关于环境搭建和基础目录结构请参照第一篇笔记。
/
|-package.json
|-index.html
|-node_modules/
|-libraries
|-...
|-DisplayData/
|-index.html
|-app/
|-DisplayComponent.js
|-main.js
|-template/
|-DisplayData.template
在Angular中,你可以为HTML模板绑定数据,这样Angular就会在数据变化时自动更新UI所显示的内容。
在这个工程中将会创建一个DisplayComponent的组件,这个组件的相关属性会实时的显示在模板上,例如:
DisplayComponent.myName="Alice";
<div>
{{myName}}
div>
那么在运行时, Directive的概念在Angular 1.x就存在了,我对它的认识比较模糊,所以直接通过一些例子来说明。Angular提供的内置执行有很多,这次使用两个:ngFor、ngIf。 可以看到 其中 ngFOr指令为iterable(可迭代的)对象的每一个元素创建一个DOM元素。Angular会自动把你对names数组所做的改动映射到DOM,例如添加、删除、排序。 ‘#name’:通过此变量引用可迭代对象的每一个值。 此时(2016-2-19)官方文档的此处内容有误,应将*ng-for改为*ngFor,其他大都也试用这个规则,感谢Neil,Wai Ha Lee,Günter Zöchbauer,Mark Rajcok。 ngIf指令通过判断你该出的表达式从而添加或删除DOM元素,它同样是实时的。 当names的长度大于3时显示 Angular采用MVVM架构,关于MVC、MVVM之类的探讨在网络上有很多,但是大多数看完后仍然一头雾水。我大概说一下我的看法供大家参考。 如果你不想将template直接写在代码中,那么可以将其单独放入文件: 这类似于第一篇笔记中给介绍Component的内容,不同的是template变成了templateUrl。templateUrl的值为所引用模板文件的URL。 将Model直接编码在Controller里是不恰当的,我们需要为Model创建一个新的类,并将它注入到控制器中: 这个Component(作为Controller)没有将数据定义写在Class中,而是放在了外面(或单独的文件中)。在需要创建Component实例的时候将data作为参数传入。 说了这么多终于可以用于实践了,之前没有创建文件进行实际操作是因为代码要改来改去以说明不同的内容,这样多个版本反而不利于理解,现在我把本文所有内容糅合在一起。 建立/DisplayData/app/DisplayComponent.js: 建立/DisplayData/app/main.js: 建立/DisplayData/app/template/DisplayData.template: 在/下执行Directive(指令)
先来说说Directive能实现什么,现在我们想在一个页面上显示人名单,人名存在一个数组中。在PHP中我们可能要通过代码控制页面的输出,或者使用模板引擎。在Angular中同样是很方便的,我们可以把这个遍历输出HTML的过程声明式的写入模板中。
例如: <ul>
<li *ngFor="#name of names">
{{ name }}
li>
ul>
中写入了一个元素,但是这个
元素中存在ngFor指令,其含义是将数组names中的每个元素进行遍历,根据name输出多个
。
其结果类似: <ul>
<li>
name1
li>
<li>
name2
li>
<li>
name3
li>
<li>
nameN
li>
ul>
{name}
的作用如前面单向绑定中所说,显示为变量name的内容,name依次迭代names中的元素。ngFor
<ul>
<li *ngFor="#name of names">
{{ name }}
li>
ul>
‘of names’:使用当前控制器(组件)的数组names作为可迭代对象。 ngIf
<p *ngIf="names.length > 3">
You have many friends!
p>
及其内容。
template、component和data的分离
MVVM(与MVC)
MVC架构将工程分为模型、视图、控制器,他们彼此分离便于调整。C起到MV的粘合剂的作用,它将数据拿出来,整合,并且包含了业务逻辑。MVC架构是对称的,C对MV的作用是同等的,它处在MV的中间。
MVVM就是Model View View-Model,显而易见,C不见了,因为C的作用被改变(或削弱)了。在Angular中主要体现在数据的自动绑定,传统的C不再需要操心如何将数据传送到View中,它主要做好与Model的交互和业务逻辑就好了。如果说MVC是平衡的,现在MVVM重心向M倾斜(这是从开发做所做的工作量来看,实际上它们最后完成了同样的工作,并没有什么区别)。从字面上开,我将VM解释为“view的model”。
在一个博客的场景中:
Model有分类、文章、评论这三个部分。
View有首页、分类页、文章页(评论和文章在一起)。
View-Model根据View有首页、分类页、文章页,但是他们主要由数据和业务逻辑组成,首页VM从M拿过来所有的分类、热门的文章(摘要而不是全文)以及热门评论。分类页VM从Model拿来所有分类,文章页VM拿来某一篇文章的全文、推荐文章的摘要、文章的评论。他们还要负责诸如访问统计、发表删除文章及评论的业务逻辑。他们不用担心和View的交互,因为这变得自动(透明)了。所以说我认为VM是“view的model”,外加业务逻辑。 如何分离
模板文件
(function(app){
app.DisplayComponent =
ng.core.Component({
selector:'display',
templateUrl:'/DisplayData/app/template/DisplayData.template'
})
.Class({
constructor:function(friends){}
});
})(window.app || (window.app = {}));
data分离
function FriendsService() {
this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
}
(function(app){
app.DisplayComponent =
ng.core.Component({
selector:'display',
providers: [FriendsService],
templateUrl:'/DisplayData/app/template/DisplayData.template'
})
.Class({
constructor:function(friends){
this.names = friends.names;
}
});
app.DisplayComponent.parameters = [[FriendsService]];
})(window.app || (window.app = {}));
此时(2016-2-19),官方文档中错误的将providers写为appInjector,感谢M.Svrcek,Klas Mellbourn,Mark Rajcok。构建工程
建立/DisplayData/index.html:<html>
<head>
<title>Display Datatitle>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="/node_modules/es6-shim/es6-shim.min.js">script>
<script src="/node_modules/angular2/bundles/angular2-polyfills.js">script>
<script src="/node_modules/rxjs/bundles/Rx.umd.js">script>
<script src="/node_modules/angular2/bundles/angular2-all.umd.js">script>
<script src='/DisplayData/app/DisplayComponent.js'>script>
<script src='/DisplayData/app/main.js'>script>
head>
<body>
<display>Loading...display>
body>
html>
function FriendsService() {
this.names = ["Aarav", "Martín", "Shannon", "Ariana", "Kai"];
}
(function(app){
app.DisplayComponent =
ng.core.Component({
selector:'display',
providers: [FriendsService],
templateUrl:'/DisplayData/app/template/DisplayData.template'
})
.Class({
constructor:function(friends){
this.myName="Alice";
this.names = friends.names;
}
});
app.DisplayComponent.parameters = [[FriendsService]];
})(window.app || (window.app = {}));
(function(app){
document.addEventListener('DOMContentLoaded',function(){
ng.platform.browser.bootstrap(app.DisplayComponent);
});
})(window.app || (window.app = {}));
<p>My name: {{ myName }}p>
<p>Friends:p>
<ul>
<li *ngFor="#name of names">
{{ name }}
li>
ul>
<p *ngIf="names.length > 3">You have many friends!p>
npm start
。
在这个工程中我没有手动创建DisplayComponent的实例,Angular将在DOM和你定义的类结合的时候自动创建相关实例并将属性和模板绑定。