本文基于Angular 2的Alpha版本,该版本现已过时。 有关最新教程,请参阅文章Angular 2教程:使用Angular CLI创建CRUD应用程序 。
当前稳定的Angular版本(即Angular 1.x)是使用ES5的功能构建的,旨在在大多数浏览器(包括某些较旧版本的IE)上运行。 该框架必须创建自己的模块系统,抽象一些语言功能,并提供一个高度抽象且基于配置的界面才能使用。
Angular 1的所有优点仍然可以在Angular 2中使用,但框架更简单。 Angular 2的构建具有ES6(和ES7)的功能,考虑了Web组件以及针对常绿浏览器的功能。
TypeScript是一种类型化的JavaScript超集合,由Microsoft构建和维护,并由AngularJS团队选择进行开发。 类型的存在使用TypeScript编写的代码不易出现运行时错误。 最近,对ES6的支持已大大改善,并且还添加了ES7的一些功能。
在本文中,我们将看到如何使用Angular 2和TypeScript来构建一个简单的应用程序。 由于Angular 2仍处于Alpha状态,因此本文中显示的代码片段的语法可能会在到达稳定版本之前发生变化。 本文开发的代码可在GitHub上获得 。
Angular 2基础
Angular 2的构建考虑了简单性。 团队删除了许多有关Angular 1的食谱,使我们认为“我们为什么要这样做?” (如果您想知道已删除的内容,建议您看一下Igor和Tobias的名为Angular 2.0 Core会话的视频)。 现在,该框架由一小组构建块和一些遵循的约定组成。
Angular 2中存在的构建基块是:
- 组件:组件类似于Angular 1中的指令。它是通过Web组件的功能构建的。 每个组件都有一个视图和逻辑。 它可以与服务交互以实现其功能。 可以将服务“依赖注入”到组件中。 就组件而言,必须使用的任何内容都必须是该组件实例上的公共成员。 组件使用属性绑定来检查值中的更改并根据更改进行操作。 组件可以处理事件,事件处理程序是组件类中定义的公共方法。
- 服务:服务是一个简单的ES6类,带有一些用于依赖注入的注释。
与Angular 1中一样,Angular 2使用依赖注入来获取对象的引用。 由于scope
已从框架中删除,因此我们没有摘要循环运行。 因此,在非Angular环境中工作时,我们无需继续调用scope.$apply
。 Angular 2使用Zone.js进行更改,并且该库知道何时执行操作。
Angular 2应用程序从一个组件开始,该应用程序的其余部分分为几个组件,这些组件被加载到根组件中。
如果您想了解更多有关Angular 2的基础知识,请查看Victor Savkin的博客文章有关Angular 2的核心概念 。
配置
在撰写本文时,Angular 2仍处于alpha版本,因此框架和其周围的资源仍然很原始。 他们将进行许多更改,并在准备投入生产时会变得更好。
Angular 2和TypeScript有大量的种子项目可以开始使用。 我认为Elad Katz撰写的这篇文章可能是进行一些练习的良好起点。 首先,如果要遵循本教程,请克隆此存储库。 然后,按照readme
文件中提到的说明安装和运行种子项目。
仓库:
- 包含使用TypeScript的基本Angular 2应用程序
- 使用JSPM / SystemJS在页面上加载依赖项
- 使用TSD引用库的TypeScript定义文件,并在名为
angular2.temp.d.ts
的本地文件中定义Angular 2缺少的定义 - 召回要在Angular中使用的Express REST API
- 使用Gulp将TypeScript代码转换为ES5并启动Node.js服务器
- 包含源TypeScript文件,该文件位于scripts文件夹内,而公用文件夹用于存储转译的文件。
如何取得成就
构建Express API
现在您已经了解了Angular 2是什么,并且还克隆了种子项目,让我们对其进行修改。 我们将构建一个简单的应用程序,将您的成就固定在董事会上。 首先,让我们添加Express API来获取和添加成就。 当我分叉存储库并修改了种子项目以添加基本的Express API时,您将看到一个提供所有成就现有列表的端点。 要发布新成就,我们需要添加一个端点。
要完成第一个任务,请打开server.js
文件并添加以下代码段:
app.post('/api/achievements', function(request, response){
achievements.push(JSON.parse(request.body));
response.send(achievements);
});
由于Angular 2的Http
API仍然很原始,它以纯文本形式发布数据。 因此,让我们添加一个bodyParser
中间件以从请求主体中读取文本:
app.use(bodyParser.text({
type: 'text/plain'
}));
修改启动组件和路由
index.html
文件是应用程序的起点。 该文件的主体部分将加载bootstrap
脚本并创建my-app
组件。 该组件又将其他组件加载到应用程序中。 bootstrap.ts
文件使用主要组件引导AngularJS应用程序。 如您所见,其他模块导出的所需注射剂将传递到函数中。 这使得这些模块导出的服务和指令可用于my-app
所有子组件。 我们将使用一个form
应用程序,为此我们需要添加formInjectables
模块导出angular2/forms
的注射剂的列表:
import {formInjectables} from 'angular2/forms';
bootstrap(MyApp, [routerInjectables, httpInjectables, formInjectables, AchievementsService]);
项目的启动组件位于app
文件夹内。 该组件上有两个注释:
- 组件:它包含组件的配置属性,例如选择器,属性名称,事件名称和注入组件的列表。 选择器的值可以与HTML标记中使用的字符串相同,不需要使用驼峰式
- 视图:视图注释将加载组件的视图部分所需的数据。 它包括一个HTML模板(可以是内联或模板URL)和组件所需的指令列表。
在下面,您可以看到相关代码:
@Component({
selector: 'my-app'
})
@View({
templateUrl: _settings.buildPath + '/components/app/app.html',
directives: [RouterLink, RouterOutlet]
})
my-app
组件必须定义应用程序的路由,并提供一个占位符以加载子视图。 可以在MyApp
类内部使用Router
服务定义路由。 以下代码段定义了应用程序所需的两条路径:
export class MyApp {
constructor(@Inject(Router) router: Router) {
router.config([
{ path: '', as: 'home', component: Home },
{ path: '/add', as: 'add', component: Add }
]);
}
}
由于尚未add
组件,因此如果您现在尝试运行该应用程序,将会遇到一些问题。 我们需要在components文件夹内创建一个新文件夹,并将其命名为add
。 然后,我们在此文件夹中添加两个文件: add.ts
和add.html
。 最后,将以下代码段添加到add.ts file
(稍后我们将添加更多代码):
import {Component, View} from 'angular2/angular2';
import { _settings } from '../../settings'
import {FormBuilder, Validators, formDirectives, ControlGroup} from 'angular2/forms';
import {Inject} from 'angular2/di';
import {Router} from 'angular2/router';
import {AchievementsService} from '../../services/achievementsService';
@Component({
selector: 'add',
injectables: [FormBuilder]
})
@View({
templateUrl: _settings.buildPath + '/components/add/add.html',
directives:[formDirectives]
})
export class Add {
}
该组件的视图将具有一个表单,该表单接受要另存为新成就的输入。 因此,将以下HTML添加到此页面:
<div>Add New Achievement</div>
<br />
<form>
<div class="input-group">
<span>Title</span>
<input type="text" id="title" class="form-control" />
</div>
<div class="input-group">
<span>Type</span>
<input type="text" id="type" class="form-control" />
</div>
<div class="input-group">
<span>From</span>
<input type="text" id="from" class="form-control" />
</div>
<div> </div>
<div class="input-group">
<input type="submit" value="click" class="btn btn-primary" />
<input type="reset" value="Reset" class="btn" >
</div>
</form>
在视图中,我们需要创建用于在页面之间导航的链接。 router-link
属性组件可帮助我们完成此任务。 我们需要将组件的名称分配给属性,它会根据先前为组件配置的路径来构建链接。
<ul class="nav navbar-nav">
<li>
<a router-link="home">Home</a>
</li>
<li>
<a router-link="add">Add</a>
</li>
</ul>
我们在根组件中需要的HTML代码的最后一部分是route-outlet
元素。 这是在视图之间导航时将加载子组件的地方。
<router-outlet></router-outlet>
列出所有成就
现在,让我们修改home组件以在墙上以固定框的形式显示所有成就的列表。 我们将使用Bootstrap设置此页面的样式。 Bootstrap的CSS已从CDN加载到index.html
。
在使用UI之前,让我们创建一个服务以将Ajax请求发送到Express.js API以与数据进行交互。 我们在services文件夹下有一个名为dummyService
的文件。 将其重命名为achievementsService
,并将文件中的类重命名为AchievementsService
。 将以下代码添加到该文件。 这段代码为服务设置了依赖注入,并添加了一种从服务中获取所有成就的方法:
import {Component, View} from 'angular2/angular2';
import { Inject} from 'angular2/di';
import {Http} from 'angular2/http';
export class AchievementsService {
constructor( @Inject(Http) private http: Http) {
}
getAllAchievements(): any {
var path = '/api/achievements';
return this.http.get(path);
}
}
Http
类的方法不返回promise,而是可观察的。 后者是具有内置功能的对象,可在发生某些更改时发出通知。 home组件需要AchievementsService
和NgFor
指令的对象来检索和显示成就列表。
要继续进行该项目, home.ts
用以下内容替换home.ts
的代码:
import {Component, View, NgFor} from 'angular2/angular2'; import { _settings } from '../../settings' import {AchievementsService} from '../../services/achievementsService'; import {Inject} from 'angular2/di'; @Component({ selector: 'home', injectables: [AchievementsService] }) @View({ templateUrl: _settings.buildPath + "/components/home/home.html", directives: [NgFor] }) export class Home { achievements: Array
; constructor( @Inject(AchievementsService) private achievementsService: AchievementsService) { achievementsService.getAllAchievements() .map(r => r.json()) .subscribe(a => { this.achievements = a; }); } }
在可观察对象发送通知之后,将调用上述片段中添加的订阅回调。 区域了解可观察对象的工作方式,并在可观察对象设置值后更新UI。 文件home.html
的标记非常简单,如下所示:
<div class="row">
<div *ng-for="#achievement of achievements" class="thumbnail col-md-3 col-sm-3 col-lg-3">
<span class="glyphicon glyphicon-pushpin"></span>
<div class="caption">
<strong>{{achievement.title}}</strong>
</div>
<p class="text-center">Level: {{achievement.type}}</p>
<p class="text-center">From: {{achievement.from}}</p>
</div>
</div>
上面代码段中的所有内容看起来都很熟悉,但div
元素上的两个特殊字符包含ng-for
。 这些符号的含义是:
-
ng-for
前面的星号表示元素内的内容将被注册为模板 - 记录变量实现前面的哈希符号使其成为局部变量。 可以在模板内部用于数据绑定
让我们保存这些更改并运行应用程序。 您将以方框的形式查看成就列表。
增加新成就
我们需要有一个接受成就详细信息的form
,并在提交时将这些详细信息发送到Express服务器。 将以下方法添加到AchievementsService
以将数据发布到服务器:
addAnAchievement(newAchievement) {
var path = '/api/achievements';
return this.http.post(path, JSON.stringify(newAchievement));
}
add
组件视图将执行以下任务:
- 接受表单中的值并将其发布到Express服务器
- 成功插入值后,将用户重定向到主屏幕
可以在Angular 2中以多种方式创建和管理表单。它们可以是模板驱动,模型驱动和数据驱动。 讨论这些方法的更多细节不在本文的讨论范围之内,但是,如果您有兴趣,在本项目中,我们将使用模型驱动的方法。 尽管我们不会在本文中使用验证,但是您很高兴知道Angular 2中的表单也支持验证。
在模型驱动方法中,我们需要创建一个要绑定在表单上的模型对象,并声明性地将其附加到表单。 表单中的字段绑定到模型对象的属性。 模型对象的值传递到服务,以将其发送到服务器。
您需要执行的下一步是打开文件add.ts
并在Add
类中添加以下代码:
addAchievementForm: any;
constructor( @Inject(FormBuilder) private formBuilder: FormBuilder,
@Inject(Router) private router: Router,
@Inject(AchievementsService) private achievementsService: AchievementsService) {
this.addAchievementForm = formBuilder.group({
title: [''],
type: [''],
from: ['']
});
}
addAchievement() {
this.achievementsService.addAnAchievement(this.addAchievementForm.value)
.map(r => r.json())
.subscribe(result => {
this.router.parent.navigate('/');
});
}
addAchievementForm
上的属性addAchievementForm
必须在表单上使用。 该对象的属性将使用ng-control
指令附加到表单内的ng-control
。 方法addAchievement
使用表单模型对象将在屏幕上输入的值传递给服务器,并在收到响应后将用户发送到主屏幕。
您可能已经注意到,我们没有处理HTTP请求的错误情况。 这是因为该功能在HTTP API中尚不可用,但是将来肯定会变得更好。
现在,打开文件app.html
并修改form元素,如下所示:
<form (ng-submit)="addAchievement()" [ng-form-model]="addAchievementForm">
在上面的代码段中,围绕ng-submit
的圆括号表示这是一个事件。 当用户提交form
时,将调用分配给它的函数。 ng-form-model
指令周围的方括号表示该值绑定到组件实例的属性。
现在,唯一未决的更改是将模型对象的字段附加到输入控件。 以下代码片段显示了标题的修改后的输入文本框,并相应地修改了其他控件:
<input type="text" id="title" ng-control="title" class="form-control" />
最后,保存所有更改并运行应用程序。 您现在应该可以添加新成就。
结论
Angular 2包含了前端世界的最新和最伟大的技术。 另外,通过使用TypeScript编写代码,可以提高开发人员的生产率。 如我们所见,该框架已完全重写,可以帮助您以更简单的方式完成许多事情。 由于该框架仍处于Alpha状态,因此建议您不要在正式生产的应用程序中使用它。 请耐心等待,看看AngularJS团队如何塑造自己的孩子。
From: https://www.sitepoint.com/getting-started-with-angular-2-using-typescript/