1.启动server:
进入switchingToNG2/switching-to-angular2目录,运行npm start,那么打开浏览器,进入红色框的链接。
2.进入switching-to-angular2/app/ch4/ts/todo-app目录。
app.ts:
todo组件分为导入、接口定义、顶层组件、控制器、启动5个部分。
//导入 import {Component} from '@angular/core'; import {bootstrap} from '@angular/platform-browser-dynamic'; //接口定义 interface Todo { completed: boolean; label: string; } //顶层组件 @Component({ selector: 'app', templateUrl: './app.html', styles: [ `ul li { list-style: none; } .completed { text-decoration: line-through; }` ] }) //控制器 class TodoCtrl { todos: Todo[] = [{ label: 'Buy milk', completed: false }, { label: "Save the world", completed: false }]; name: string = 'John'; addTodo(label) { this.todos.push({ label, completed: false }) } removeTodo(idx) { this.todos.splice(idx, 1); } toggleCompletion(idx) { let todo = this.todos[idx]; todo.completed = !todo.completed; } } //启动 bootstrap(TodoCtrl);
(1)组件样式
我们直接在组件装饰器加入styles属性。
app/ch4/ts/todo-app/app.ts的样式代码:
@Component({ selector: 'app', templateUrl: './app.html', styles: [ `ul li { list-style: none; } .completed { text-decoration: line-through; }` //styles属性,值为数组。 ] })
(2)组件控制器
app.ts控制器代码:
//控制器 class TodoCtrl { todos: Todo[] = [{ label: '呼风唤雨', completed: false }, { label: "保护妹妹", completed: false }]; //todos数组。包含两个元素,每个元素的变量指定为Todo。 name: string = '爱莎'; //name属性 addTodo(label) { this.todos.push({ label, completed: false }) } //用于添加元素 removeTodo(idx) { this.todos.splice(idx, 1); } //用于移除元素 toggleCompletion(idx) { let todo = this.todos[idx]; todo.completed = !todo.completed; } //切换完成或者未完成 }
(3)模板app.html内容:
<h1>你好 {{name}}!</h1> <p> 添加todo: <input #newtodo type="text"> <button (click)="addTodo(newtodo.value); newtodo.value = ''">Add</button> </p> <p>to-do清单:</p> <ul> <!--遍历todos数组--> <li *ngFor="let todo of todos; let index = index" [class.completed]="todo.completed"> <input type="checkbox" [checked]="todo.completed" (change)="toggleCompletion(index)"> {{todo.label}} </li> </ul>
● <li *ngFor="let todo of todos; let index = index" [class.completed]="todo.completed"> 这里使用了index索引。
● (change)="toggleCompletion(index)" 绑定了toggleCompletion函数到change事件上。
● [checked]="todo.completed" 绑定了控制器的todos数据的completed到checked属性上。
● [class.completed]="todo.completed" 意思是如果todo.completed为true,那么添加completed类。angular也允许绑定style和attribute的。
最后启动app的时候,要把控制器传进去。
//启动 bootstrap(TodoCtrl);
打开http://localhost:5555/dist/dev/ch4/ts/todo-app/,结果为
3.组件的用户交互
实现toggleCompletion方法。它是控制器里定义的,所以直接使用咯。
toggleCompletion(idx) { let todo = this.todos[idx]; todo.completed = !todo.completed; } //切换完成或者未完成的状态
实现addToDo方法,用来添加todo元素。
addTodo(label) { this.todos.push({ label, completed: false }) } //用于添加元素
通过button按钮添加元素如图:
4.app组件的切分
先来看一下指令API的输入输出。可以把指令接受的属性看成输入。把指令触发的事件看成输出。使用第三方库的指令时最主要的关注点就是输入和输出,这些内容构成了指令的API。
如果把todo应用切分成多个独立的组件,组件之间存在交互,那么分析一下这个todo应用咯。
最外层的方框代表整个todo应用。内部的第一个方框有一个组件,用来新建todo项目。下面的方框用来存储所有的项目。
根据分析,我们可以定义3个组件:
●TodoApp
●InputBox
●TodoList
5.InputBox组件:关注输入和输出
app/ch4/ts/inputs-outputs/app.ts完整的代码:
//导入 import {Component, Input, Output, EventEmitter} from '@angular/core'; import {bootstrap} from '@angular/platform-browser-dynamic'; //todo接口 interface Todo { completed: boolean; label: string; } //InputBox组件 @Component({ selector: 'input-box', template: ` <input #todoInput [placeholder]="inputPlaceholder"> <button (click)="emitText(todoInput.value); todoInput.value = '';"> {{buttonLabel}} </button> ` }) class InputBox { @Input() inputPlaceholder: string; @Input() buttonLabel: string; @Output() inputText = new EventEmitter<string>(); emitText(text: string) { this.inputText.emit(text); } } //ToDoList组件 @Component({ selector: 'todo-list', template: ` <ul> <li *ngFor="let todo of todos; let index = index" [class.completed]="todo.completed"> <input type="checkbox" [checked]="todo.completed" (change)="toggleCompletion(index)"> {{todo.label}} </li> </ul> `, styles: [ `ul li { list-style: none; } .completed { text-decoration: line-through; }` ] }) class TodoList { @Input() todos: Todo[]; @Output() toggle = new EventEmitter<Todo>(); toggleCompletion(index: number) { let todo = this.todos[index]; this.toggle.emit(todo); } } //TodoApp组件 @Component({ selector: 'todo-app', directives: [TodoList, InputBox], template: ` <h1>Hello {{name}}!</h1> <p> Add a new todo: <input-box inputPlaceholder="New todo..." buttonLabel="Add" (inputText)="addTodo($event)"> </input-box> </p> <p>Here's the list of pending todo items:</p> <todo-list [todos]="todos" (toggle)="toggleCompletion($event)"> </todo-list> ` }) class TodoApp { todos: Todo[] = [{ label: 'Buy milk', completed: false }, { label: "Save the world", completed: false }]; name: string = 'John'; addTodo(label: string) { this.todos.push({ label, completed: false }); } toggleCompletion(todo: Todo) { todo.completed = !todo.completed; } } //启动 bootstrap(TodoApp);