Angular学习教程-英雄之旅
官网链接
https://angular.cn/tutorial
文章目录
一、能学习到
在本教程的最后,将完成下列工作:
- 使用 Angular 的内置指令来显示 / 隐藏元素,并显示英雄数据的列表。
- 创建 Angular 组件以显示英雄的详情,并显示一个英雄数组。
- 为只读数据使用单向数据绑定。
- 添加可编辑字段,使用双向数据绑定来更新模型。
- 把组件中的方法绑定到用户事件上,比如按键和点击。
- 让用户可以在主列表中选择一个英雄,然后在详情视图中编辑他。
- 使用管道来格式化数据。
- 创建共享的服务来管理这些英雄。
- 使用路由在不同的视图及其组件之间导航。
二、创建项目
ng new heroes --skip-install
cd heroes
npm set registry https://registry.npmjs.org/
npm cache clean --force
npm install
- 启动应用服务器
ng serve --open
- 让整个应用保持一致的外观。
在src/styles.css (excerpt)下添加
/* Application-wide Styles */
h1 {
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
}
h2, h3 {
color: #444;
font-family: Arial, Helvetica, sans-serif;
font-weight: lighter;
}
body {
margin: 2em;
}
body, input[type="text"], button {
color: #333;
font-family: Cambria, Georgia;
}
/* everywhere else */
* {
font-family: Arial, Helvetica, sans-serif;
}
三、英雄编辑器
Part1
1.创建英雄列表组件
- ng generate component heroes
CLI 创建了一个新的文件夹 src/app/heroes/
,并生成了 HeroesComponent
的四个文件。
app/heroes/heroes.component.ts
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.scss']
})
export class HeroesComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
CLI 自动生成了三个元数据属性:
selector
— 组件的选择器(CSS 元素选择器)templateUrl
— 组件模板文件的位置。styleUrls
— 组件私有 CSS 样式表文件的位置。
2.添加 hero
属性
heroes.component.ts
export class HeroesComponent implements OnInit {
hero = 'Windstorm';
constructor() {
}
ngOnInit(): void {
}
}
4.显示英雄
heroes.component.html
{
{hero}}
src/app/app.component.html
<h1>1</h1>
<h1>{
{title}}</h1>
<app-heroes></app-heroes>
5.启动
Part2
1.创建Hero类
新建文件src/app/hero.ts
export interface Hero {
id: number;
name: string;
}
2.把组件的 hero
属性的类型重构为 Hero
。
src/app/heroes/heroes.component.ts
import {
Component, OnInit } from '@angular/core';
import {
Hero } from '../hero'
@Component({
selector: 'app-heroes',
templateUrl: './heroes.component.html',
styleUrls: ['./heroes.component.scss']
})
export class HeroesComponent implements OnInit {
hero: Hero = {
id: 1222,
name: 'Windstorm'
};
constructor() {
}
ngOnInit(): void {
}
}
3.显示 hero
对象
修改模板中的绑定,以显示英雄的名字
src/app/heroes/heroes.component.html
<!-- uppercase把文本转换成全大写形式。 -->
<h2>{
{ hero.name | uppercase}} Details</h2>
<div><span>id: </span>{
{hero.id}}</div>
<div><span>name: </span>{
{hero.name}}</div>
-
绑定表达式中的
uppercase
位于管道操作符( | )的右边,用来调用内置管道UppercasePipe
。 -
管道 是格式化字符串、金额、日期和其它显示数据的好办法。
4.双向绑定
想让这种数据流动自动化,就要在表单元素 <input>
和组件的 hero.name
属性之间建立双向数据绑定。
src/app/heroes/heroes.component.html
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name"/>
</label>
</div>
<!-- uppercase把文本转换成全大写形式。 -->
<h2>{
{ hero.name | uppercase}} Details</h2>
<div><span>id: </span>{
{hero.id}}</div>
<div><span>name: </span>{
{hero.name}}</div>
-
[(ngModel)] 是 Angular 的双向数据绑定语法。
-
这里把
hero.name
属性绑定到了 HTML 的 textbox 元素上,以便数据流可以双向流动:从hero.name
属性流动到 textbox,并且从 textbox 流回到hero.name
。
5.缺少 FormsModule
发现报错
- 导入
FormsModule
app.module.ts
import {
NgModule } from '@angular/core';
- 然后把
FormsModule
添加到@NgModule
元数据的imports
数组中,这里是该应用所需外部模块的列表。
imports: [
BrowserModule,
FormsModule,
AppRoutingModule
],
最后结果
输入框和其他hero.name完成双向绑定
四、显示英雄列表
Part1
1.创建模拟(mock)的英雄数据
创建一些模拟的英雄数据,并假装它们是从服务器上取到的。
src/app/mock-heroes.ts
import {
Hero } from './hero';
export const HEROES: Hero[] = [
{
id: 11, name: 'Dr Nice' },
{
id: 12, name: 'Narco' },
{
id: 13, name: 'Bombasto' },
{
id: 14, name: 'Celeritas' },
{
id: 15, name: 'Magneta' },
{
id: 16, name: 'RubberMan' },
{
id: 17, name: 'Dynama' },
{
id: 18, name: 'Dr IQ' },
{
id: 19, name: 'Magma' },
{
id: 20, name: 'Tornado' }
];
2.显示这些英雄
src/app/heroes/heroes.component.ts
打开 HeroesComponent
类文件,并导入模拟的 HEROES
。
import {
HEROES } from '../mock-heroes';
往类中添加一个 heroes
属性,这样可以暴露出这个 HEROES
数组,以供绑定。
export class HeroesComponent implements OnInit {
heroes = HEROES;
//...
}
3.使用 *ngFor 列出这些英雄
heroes.component.html
<h2>My Heroes</h2>
<ul class="heroes">
<li *ngFor="let hero of heroes">
<span class="badge">{
{hero.id}}</span> {
{hero.name}}
</li>
</ul>
<li>
就是*ngFor
的宿主元素。heroes
就是来自HeroesComponent
类的列表。- 当依次遍历这个列表时,
hero
会为每个迭代保存当前的英雄对象。
4.可能会遇到的错误
- 意思是不能读取到mock-heroes.ts
- 解决方法
- 在tsconfig.app.json的files或include下添加这句话
“src/app/mock-heroes.ts”
- 本人添加后可以运行
- 运行后注释后也可运行(有点莫名其妙)
- 可能是include下的
"src/**/*.d.ts"
本来就可以读取到mock-heroes.ts
文件,但是一开始没有读取成功。
4.效果如下
Part2
1.给英雄列表“美容”
src/app/heroes/heroes.component.css
/* HeroesComponent's private CSS styles */
.heroes {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 15em;
}
.heroes li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroes li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.heroes li.selected {
background-color: #CFD8DC;
color: white;
}
.heroes li.selected:hover {
background-color: #BBD8DC;
color: white;
}
.heroes .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color:#405061;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
2.主从结构
当用户在主列表中点击一个英雄时,该组件应该在页面底部显示所选英雄的详情。
在本节,你将监听英雄条目的点击事件,并更新英雄的详情。
①添加 click
事件绑定
src/app/heroes/heroes.component.html
<li *ngFor="let hero of heroes" (click)="onSelect(hero)">
②添加 click
事件处理器
src/app/heroes/heroes.component.ts
selectedHero: Hero| undefined;
onSelect(hero: Hero): void {
this.selectedHero = hero;
}
③添加详情区
在 heroes.component.html
中该列表的紧下方,添加如下代码:
src/app/heroes/heroes.component.html
<!-- 详情区 -->
<div *ngIf="selectedHero">
<h2>{
{selectedHero.name | uppercase}} Details</h2>
<div><span>id: </span>{
{selectedHero.id}}</div>
<div>
<label>name:
<input [(ngModel)]="selectedHero.name" placeholder="name" />
</label>
</div>
</div>
[class.selected]="hero === selectedHero"
给所有的英雄添加样式。
效果展示
五、主从组件
此刻,HeroesComponent
同时显示了英雄列表和所选英雄的详情。
把所有特性都放在同一个组件中,将会使应用“长大”后变得不可维护。 你要把大型组件拆分成小一点的子组件,每个子组件都要集中精力处理某个特定的任务或工作流。
本页面中,你将迈出第一步 —— 把英雄详情移入一个独立的、可复用的 HeroDetailComponent
。
1.制作 HeroDetailComponent
ng generate component hero-detail
①编写模板
src/app/hero-detail/hero-detail.component.html
<div *ngIf="hero">
<h2>{
{hero.name | uppercase}} Details</h2>
<div><span>id: </span>{
{hero.id}}</div>
<div>
<label>name:
<input [(ngModel)]="hero.name" placeholder="name"/>
</label>
</div>
</div>
②添加 @Input() hero
属性
src/app/hero-detail/hero-detail.component.ts
import {
Hero } from '../hero';
hero
属性必须是一个带有 @Input()
装饰器的输入属性,因为外部的 HeroesComponent
组件将会绑定到它。
src/app/hero-detail/hero-detail.component.ts
import {
Component, OnInit, Input } from '@angular/core';
@Input() hero: Hero;
③修改 HeroesComponent
的模板
app/heroes/heroes.component.html
<app-hero-detail [hero]