国内 Angular2 资料比较少,这里看到一篇不错的入门文章就分享过来了 —— Angular 2 快速上手,这里面还有不少有关于 Angular2 的文章,感兴趣的朋友能够去看一看css
目前angular2已经来到了beta版,这意味着它已经作好了开发出稳定应用的准备了。和angular1.x相比,它发生了许多颠覆性的变化,angular2的官方网站上,有一个5分钟快速开始教程(angular.io),有兴趣的朋友能够去开一下,帮助你快速的了解angular2。在本文中,我将会经过制做一个简单的小网站,来为你们展现angular2的新特性,带领你们走入angular2的全新世界。html
如今有两种主要的方法配置angular2的应用程序,一个是经过systemjs,而另外一个则是webpack。为了简单起见,在本文中将会使用systemjs。
你可使用ES五、EcmaScript 2015 或者 TypeScript来开发你的angular2应用,angular2的团队的推荐是使用TypeScript开发。在使用TypeScript以前,须要完成一些配置工做,虽然你会感受到有些繁琐,可是用起来你仍是会感到驾轻就熟的,你的代码也将会更加清晰明了。
咱们先借用在angular2官网的教程中使用的工程 Tour of Heroes 来开始咱们的征程。
你能够经过git下载这个工程,当你下载下来以后,第一件事应该是用npm i
命令来初始化项目。node
由于咱们是用TypeScript编写咱们的程序,因此咱们先得在咱们的工程中配置TypeScript,告诉编译器如何产生JavaScript文件。关于配置文件中的其余属性在这里我就不赘述了,我只介绍两个最重要的属性,一个是"target":"ES5"
和"module":"system"
。target
属性将设置TypeScript编译出来的ECMAScript版本为
ES5,"module":"system"
觉得着咱们想用
system的格式来生成咱们的模块。webpack
{ "compilerOptions": { "target": "ES5", "module": "system", "sourceMap": true, "emitDecoratorMetadata": true, "experimentalDecorators": true, "moduleResolution": "node", "removeComments": false, "noImplicitAny": true, "suppressImplicitAnyIndexErrors": true }, "exclude": [ "node_modules" ] }
咱们已经定义了该如何编译TypeScript文件,接下来咱们须要在工程的 package.json 文件中添加一些选项。git
"scripts": { "tsc": "tsc", "tsc:w": "tsc -w", "lite": "lite-server", "start": "concurrent \"npm run tsc:w\" \"npm run lite\" " }
Angular2中对于我来讲最神秘的一点就是“我该如何运行个人应用?”,第二神秘的一点就是“好吧,我该如何启动个人应用程序?”github
启动咱们的应用的第一件事就是在工程的index.html
文件中引用必要的资源。除了angular的资源的以外,最重要的一环就是system.src.js
,用它来做咱们的模块加载器。web
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script> <script src="node_modules/systemjs/dist/system.src.js"></script> <script src="node_modules/rxjs/bundles/Rx.js"></script> <script src="node_modules/angular2/bundles/angular2.dev.js"></script> <script src="node_modules/angular2/bundles/router.dev.js"></script>
咱们打算经过使用systemjs
来输入咱们的启动模块。npm
<script> System.config({ packages: { app: { format: 'register', defaultExtension: 'js' } } }); System.import('app/boot') .then(null, console.error.bind(console)); </script>
在boot.ts
文件中,咱们输入了3格组件:bootstrap
、ROUTER_PROVIDERS
和AppComponent
。而后实例化了咱们的应用并指明了咱们的根组件,AppComponent
并注入了ROUTER_PROVIDERS
做为一个子模块。json
import {bootstrap} from 'angular2/platform/browser'; import {ROUTER_PROVIDERS} from 'angular2/router'; import {AppComponent} from './app.component'; bootstrap(AppComponent, [ ROUTER_PROVIDERS ]);
回到以前的index.html
文件中,<app>Loading...</app>
这一行就是咱们应用的入口标记。Angular已经实例化了AppComponent
而且将它的模板载入到了app
元素中。bootstrap
<body> <app>Loading...</app> </body>
在讲解了如何编译、配置和启动一个angular2的应用程序以后。让咱们看一看angular2中组件的组成部分,以便咱们能更好的理解AppComponent
和app
之间的联系。
Angular中的组件是angular中最基本的概念之一。一个组件控制一个视图(View)――一片为用户展现信息和响应用户反馈的网页。通常来讲,一个组件就是一个用于控制视图模板的JavaScript类。
引用(有关于组件的更多内容,你能够去阅读个人《CIDER:建立一个Angular2组件》,你将会了解到如何建立和使用你的组件)
建立组建的第一件事就是先写一个类(class),咱们先作声明,一会再来改进它。
export class AppComponent {}
接下来,咱们应该输入咱们的依赖模块。在本例中,咱们仅须要从angular2/core
中输入Component
。
import {Component} from 'angular2/core';
以后,咱们须要装饰(decorate)咱们的类。经过添加@Component
的元数据来告诉咱们的应用程序,咱们想要一个怎么样的AppComponent
。咱们将使用selector
属性为咱们的组件取一个HTML元素的名字,这样就能够经过定义好的HTML元素的名字来使用组件了。同时还须要经过templateUrl
和styleUrls
为组件设置模板和样式。最后,咱们将ROUTER_DIRECTIVES
这个指令经过directives
属性注入到组件中去。
@Component({ selector: 'app', templateUrl: 'app/app.component.html', styleUrls: ['app/app.component.css'], directives: [ROUTER_DIRECTIVES] }) export class AppComponent {}
在这个示例中,咱们还想增长为咱们的组件增长路由功能,所以咱们将会使用RouterConfig
模块,并用@RouterConfig
来装饰咱们的组件。为了可以路由,咱们须要在文件中的最顶部输入RouterConfig
、ROUTER_DIRECTIVES
、AboutComponent
、ExperimentsComponent
和HomeComponent
。
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; import {AboutComponent} from './about/about.component'; import {ExperimentsComponent} from './experiments/experiments.component'; import {HomeComponent} from './home/home.component';
咱们须要路由模块来开启路由功能以及其余的组件做为路由的目标。接下来就须要向@RouterConfig
中传入一组路由的定义,来告诉应用程序路由的路径、路由的名字和每一个路由所对应的组件。咱们为home
路由的属性useAsDefault
设置为true
,将其做为默认路由。
@RouteConfig([ {path: '/home', name: 'Home', component: HomeComponent, useAsDefault: true }, {path: '/about', name: 'About', component: AboutComponent }, {path: '/experiments', name: 'Experiments', component: ExperimentsComponent } ])
而后,咱们将StateService
和ExperimentService
输入到咱们的组件中并放入component
修饰符的providers
属性中。如下是整个 AppComponent 的代码。
import {Component} from 'angular2/core'; import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router'; import {AboutComponent} from './about/about.component'; import {ExperimentsComponent} from './experiments/experiments.component'; import {HomeComponent} from './home/home.component'; import {StateService} from './common/state.service'; import {ExperimentsService} from './common/experiments.service'; @Component({ selector: 'app', templateUrl: 'app/app.component.html', styleUrls: ['app/app.component.css'], directives: [ROUTER_DIRECTIVES], providers: [StateService, ExperimentsService], }) @RouteConfig([ {path: '/home', name: 'Home', component: HomeComponent, useAsDefault: true }, {path: '/about', name: 'About', component: AboutComponent }, {path: '/experiments', name: 'Experiments', component: ExperimentsComponent } ]) export class AppComponent {}
在完成 App 组件以后,咱们继续编写咱们的 Home 组件。首先仍是先定义一个 HomeComponent
类,同时在类中为组件的标题和内容定义两个属性。
export class HomeComponent { title: string = 'Home Page'; body: string = 'This is the about home body'; }
而后输入合适的依赖模块。
import {Component} from 'angular2/core';
以后装饰咱们的类并设置selector
和templateUrl
属性。
@Component({ selector: 'home', templateUrl: 'app/home/home.component.html' })
而后咱们将为咱们的组件引用 StateService 并使用它来存储状态两个路由之间的状态。Angular2中的依赖注入发生在该类的构造函数中,所以咱们将在构造函数中注入 StateService。Angular的每一个组件都有有生命周期的钩子(lifecycle hooks),咱们能够按顺序使用它们。在本组件中,咱们想在组件初始化的时候从 StateService 中获取和设置咱们的信息。这时候咱们须要使用ngOnInit
钩子。(有关于组件的生命周期的详细内容能够参考官网教程(https://angular.io/docs/ts/latest/guide/lifecycle-hooks.html))
import {Component} from 'angular2/core'; import {StateService} from '../common/state.service'; export class HomeComponent { title: string = 'Home Page'; body: string = 'This is the about home body'; message: string; constructor(private _StateService: StateService) { } ngOnInit() { this.message = this._StateService.getMessage(); } updateMessage(m: string): void { this._StateService.setMessage(m); } }
许多组件可能会须要访问相同的一组数据,而咱们并不想像傻瓜同样的一遍又一遍的复制粘贴一样的代码。这个时候,服务(Service)出现了。咱们须要建立一个单一的且能够重复使用的数据服务,并学会将该服务注入到咱们须要的组件中去。
将数据的存取从新包装成一个独立的服务让组件的重心倾向于对视图的支持。它能让组件的单元测试变得更加容易。
在上面的组件中,咱们常常见到一个叫StateService的东西,它究竟是什么呢?没错,它就是一个服务,接下来,让咱们一步一步的建立它。首先咱们须要声明一个叫 StateService 的类并将它暴露给咱们的应用程序。
export class StateService { private _message = 'Hello Message'; getMessage(): string { return this._message; }; setMessage(newMessage: string): void { this._message = newMessage; }; }
该服务中定义了_message
属性以及它的属性获取器(getter)和设置器(setter)。咱们要想使StateService可以注入到其余组件中去,首先须要在咱们的类中输入Injectable
,并用@Injectable
修饰咱们的类。
import {Injectable} from 'angular2/core'; @Injectable() export class StateService { private _message = 'Hello Message'; getMessage(): string { return this._message; }; setMessage(newMessage: string): void { this._message = newMessage; }; }
好了,如今服务模块也写好了,感受咱们的应用终于快完成了,最后也是最重要的一步,就是要描述应用的样子了。
我将经过home.component.html
做为切入点来简单介绍一下 Angular2 中的升级版模板语法(template syntax)。
单向数据绑定与 Angular1.x 中的形式是同样的,就是经过字符串插入。
<h1>{{title}}</h1> {{body}}
用户输入事件再也不经过在咱们的HTML标签中使用自定义的Angular指令来捕获,而是经过在插入语句中封装原生的DOM事件来捕获它们。咱们能够在下面代码中看到,我经过(click)="updateMessage(message)"
来为元素注册 click 事件,当事件触发时调用 updateMessage 方法。
<button type="submit" class="btn" (click)="updateMessage(message)">Update Message</button>
Angular2中的双向数据绑定基于单向数据绑定。以前咱们看到单向数据绑定中使用了字符串插入的方法,其实在咱们绑定一个元素的属性时,可使用方括号语法。咱们将属性绑定(组件到视图)和事件绑定(视图到组件)的方法组合起来就是双向数据绑定了。是否是很神奇?双向数据绑定的方法很简单,就是在 ngModel 用方括号和圆括号包起来变成[(ngModel)]=”message
。
<input type="text" [(ngModel)]="message" placeholder="Message">
如下是整个 home.component.html 的内容。
<h1>{{title}}</h1> {{body}} <hr> <div> <h2 class="text-error">Home: {{message}}</h2> <form class="form-inline"> <input type="text" [(ngModel)]="message" placeholder="Message"> <button type="submit" class="btn" (click)="updateMessage(message)">Update Message</button> </form> </div>
接下来,咱们须要回到 app.component.html 中,来探讨一下如何在模板语法中加入路由连接。在咱们定义一个路由的时候,每一个组件都有它对应的模板,那么问题来了,当路由到一个组件的时候,这个模板应该被放在哪里呢?这个时候,router-outlet
出现了,它告诉应用程序路由中组件的摆放位置。
<div id="container"> <router-outlet></router-outlet> </div>
在定义了路由组件的摆放位置以后,那么咱们如何从一个路由到另外一个路由呢?RouterLink 就是完成了路由的指向问题。
<h1 id="logo"> <a [routerLink]="['/Home']"></a> </h1> <div id="menu"> <a [routerLink]="['/Home']" class="btn">Home</a> <a [routerLink]="['/About']" class="btn">About</a> <a [routerLink]="['/Experiments']" class="btn">Experiments</a> </div>
整个 app.component.html 文件以下所示:
<header id="header"> <h1 id="logo"> <a [routerLink]="['/Home']"></a> </h1> <div id="menu"> <a [routerLink]="['/Home']" class="btn">Home</a> <a [routerLink]="['/About']" class="btn">About</a> <a [routerLink]="['/Experiments']" class="btn">Experiments</a> </div> <div class="color"></div> <div class="clear"></div> </header> <div class="shadow"></div> <div id="container"> <router-outlet></router-outlet> </div>
到此为止,咱们的网页算是完成了,在你拿出去炫耀以前,让咱们回顾一下咱们的制做过程:
一、咱们配置了tsconfig.json文件来讲明TypeScript该如何编译。二、咱们学习了如何简单的使用systemjs来处理模块的载入并引导咱们应用程序的启动。三、咱们了解了该如何建立 AppComponent 和 HomeComponent。四、咱们学习了如何使用 @Injectable() 建立一个可注入的服务。五、咱们稍微了解了一下Angular2中的绑定语法。六、咱们学习了如何用 router-outlet 在视图中定义路由组件存放的位置,并使用 routerLink 进行路由之间的跳转。