Angular2 是 Google 用于构建基于浏览器的复杂应用的下一代 MV* 框架。该项目是我学习 Angular2 的入门项目,我以为它很友好地表达了 Angular2 的有趣实现方式,并更易于了解和入门。它涵盖了 Angular2 的一些基本概念,包括:组件(Component)、模型(Model)、服务(Service)、管道(Pipe)、传入传出(Input / Output)以及事件播散(EventEmitter)等使用方法,并介绍了项目的基本组织结构等。html
Anguar2 可以使用 ES6 或 TypeScript 来编写,我在这里使用了 TypeScript。node
若您对本文感兴趣,也很是欢迎来个人 GitHub 主页阅读,同时也是本文的项目代码地址(https://github.com/DotHide/angular2-quickstart)git
如下罗列的是该项目中的几个重要概念:github
在 Angular2 中,Component 是咱们在页面中构建自定义元素和业务逻辑的主要方式。在 Angular1 中,咱们则是经过 directives,controllers 以及 scope 来实现,而如今全部的这一切都结合到了 Component 中。Component 中须要定义 selector 和 templete,即组件生效的标记和对应的 HTML 模板typescript
// Component 是 Angular2 提供的组件,使用前须要先 import import {Component} from "angular2/core"; @Component({ selector: 'todo-input', template: ` <div> <form (submit)="onSubmit()"> <input type="text" [(ngModel)]="todoItem.title"> </form> </div> ` })
其中 templete 使用到了多行模板的用法,即便用\
`做为模板开始结束标记npm
定义组件后须要定义相匹配的类:json
export class TodoInput { }
类名使用 UpperCamelCase,如:TodoInput,文件名及 selector 使用 DashCase,如:todo-input(.ts)bootstrap
任何 Component 在使用前须要 import,若是是组件中的组件须要在 @Component 中定义 directives,如:浏览器
@Component({ selector: 'todo-app', directives: [TodoInput], templete: '...' })
模型比较简单,通知只须要定义好构造函数及相关方法便可:bash
export class TodoModel{ constructor( public title:string = "", public status:string = "started" ){} toggle():void{ this.status = this.status == 'completed'? 'started': 'completed'; } }
这里构造函数的参数定义了 public,这样能够被其余类访问到
服务一般须要声明 @Injectable()
,通常服务也会 import 模型类
import {Injectable} from "angular2/core"; import {TodoModel} from "../models/todo-model"; @Injectable() export class TodoService { todos:TodoModel[] = [ new TodoModel("arm"), new TodoModel("battle"), new TodoModel("code", "completed"), new TodoModel("eat"), new TodoModel("fly"), new TodoModel("sleep", "completed") ]; addTodoItem(item:TodoModel) { ... } toggleTodo(todo: TodoModel) { ... } }
声明了 Injectable
以后,须要在入口函数中 inject 相关服务
bootstrap(TodoApp, [TodoService]);
即 Angular 1 中的 ng-repeat
,这里用法有些差别,如:
<ul> <li *ngFor="#todo of todoService.todos"> {{ todo }} </li> </ul>
使用 ngFor 时须要在前加 号( 号表示该动做将引发模板的变化),循环中的个体元素引用前须要添加 # 号,这些都是语法上的变化。
ngModel
用于双向绑定,使用 [(ngModel)]=
来定义,[()]
专门用于定义双向绑定。
@Component({ selector: 'todo-input', template: ` <div> <form (submit)="onSubmit()"> <input type="text" [(ngModel)]="todoItem.title"> </form> </div> ` }) export class TodoInput { todoItem:TodoModel = new TodoModel(); constructor() {} }
使用 ngModel 前须要在 class 中定义变量,变量能够是任何类型。
利用 Pipe 来筛选(filter)数据,与 Angualr1 十分相似,这里仍是使用 |
符号来定义筛选,如:
// todo-list.ts ... @Component({ selector: 'todo-list', pipes: [SearchPipe], directives: [TodoItemRender], template: `<div> <ul> <li *ngFor="#todo of todoService.todos | search "> <todo-item-render [todo]="todo" (toggle)="todoService.toggleTodo($event)"> </todo-item-render> </li> </ul> </div>` }) // search-pipe.ts ... @Pipe({ name: 'search' }) export class SearchPipe { transform(items) { // 定义转换逻辑,用于结果输出,这里是筛选出以 s 字符开头的项目 return value.filter((item) => { return item.title.startsWith('s'); }); } }
使用 Pipe 时须要先在 Component 中定义 pipes 属性,而后在 html 中使用 Pipe 的 name。
固然,这里的 Pipe 还能够传递参数,仍然以上面的为例,能够传参设定 search 的内容,如:
// search-pipe.ts ... @Pipe({ name: 'search' }) export class SearchPipe { // 增长 term 参数 transform(items, [term]) { // 定义转换逻辑,用于结果输出,这里是筛选出以 s 字符开头的项目 return value.filter((item) => { return item.title.startsWith(term); }); } }
这里分两步修改,首先修改 SearchPipe 类中的方法,增长 term 参数,而后再修改使用处的代码
// todo-list.ts ... @Component({ selector: 'todo-list', pipes: [SearchPipe], directives: [TodoItemRender], template: `<div> <ul> <li *ngFor="#todo of todoService.todos | search = 's' "> <todo-item-render [todo]="todo" (toggle)="todoService.toggleTodo($event)"> </todo-item-render> </li> </ul> </div>` })
这里咱们先看到 search 进行了赋值,咱们进一步把这个赋值变为一个输入项(@Input),这也是 Angular2 中特殊用法:
// todo-list.ts import {Component, Input} from "angular2/core"; ... @Component({ selector: 'todo-list', pipes: [SearchPipe], directives: [TodoItemRender], template: `<div> <ul> <li *ngFor="#todo of todoService.todos | search = term "> <todo-item-render [todo]="todo" (toggle)="todoService.toggleTodo($event)"> </todo-item-render> </li> </ul> </div>` }) export class TodoList { @Input() term; // 定义该项是从外部输入的 constructor(public todoService: TodoService) { } }
由此,须要在使用 TodoList 组件的地方(即外部),定义相关的属性。
<search-box (update)="term = $event"></search-box> ... <todo-list [term]="term"></todo-list>
这里表示从搜索框输入过来的值(前一个 term),被赋值到了 todo-list 的 [term]
属性中,并传递到 TodoList 类的输入项中去
事件散播,又一个 Angular2 的新特性,用于将组件内部的事件向上散播,如:
@Component({ selector: 'todo-item-render', template: ` <style> .completed { text-decoration: line-through; } </style> <span [ngClass]="todo.status">{{ todo.title }}</span> <button (click)="toggle.emit(todo)">Toggle</button> ` }) export class TodoItemRender { @Input() todo; @Output() toggle = new EventEmitter(); }
这里的 toggle 是 EventEmitter 对象,被声明为 Output 后,能够将按钮的 click 事件向上散播成为 todo-list 中该组件的 toggle 事件,其中的 $event
就是 TodoItemRender 类中声明的 todo(此 todo 又是来自外部输入),然后再触发 toggle 事件对应的业务逻辑。
请按如下步骤打开项目:
# 安装 TypeScript $ npm install -g tsd typescript # 安装项目依赖 $ npm install # 启动项目 $ npm start
琢磨调用第三方库花了些时间,这里也记录一下。以添加 lodash 库为例,须要通过以下5个步骤:
$ npm install lodash --save
安装后到
package.json
文件中查看,若有 loash 再进入下一步
$ tsd install lodash
若是没有 tsd 命令行工具,则先安装
$ npm install -g tsd
在 index.html
文件中引用:
<script src="node_modules/lodash/lodash.js"></script>
在 System.config()
中添加 path
:
System.config({ paths: { lodash: './node_modules/lodash/lodash.js' } });
在须要使用的地方 import
:
import * as _ from "lodash"; ... function (){ _.sum([4, 2, 8, 6]); // → 20 }