Angular 入门教程

原文链接:Build your first Angular app,by Angular Team。翻译时有删改。

Angular 和 React、Vue 是目前全世界最流行的三大框架之一。本文将带你手动创建一个 Anuglar App,领略 Angular 的编码方式。

环境准备

首先,确保你的电脑中安装了 LTS 版本的 Node.js,目前 Node.js 的 LTS 版本 是 v20.11.1(npm 10.2.4),推荐安装。

bash 复制代码
PS D:\learning> node -v
v20.11.1
PS D:\learning> npm -v
10.2.4

然后,全局安装 Angular CLI 程序,这是一个 npm 包。

bash 复制代码
PS D:\learning> npm install -g @angular/cli 
PS D:\learning> npm list -g
C:\Users\张宝\AppData\Roaming\npm
├── @angular/cli@17.3.0

安装成功后,就有一个全局 ng 指令可以使用了。

最后就是代码编辑器了,推荐 VS Code,同时安装插件 Angular Language Service,它会提供代码自动提示支持。

这样,就完成了 Angular 项目的环境准备。

创建项目

首先,使用 ng new 命令创建一个全新的项目 my-first-angular-app

bash 复制代码
PS D:\learning> ng new my-first-angular-app

一路 Enter,采用默认选项就好。

进入项目,使用 VS Code 打开。

bash 复制代码
PS D:\learning> cd .\my-first-angular-app\
PS D:\learning\my-first-angular-app> code .

安装依赖,启动并在浏览器中打开项目。

bash 复制代码
PS D:\learning\my-first-angular-app> npm install
PS D:\learning\my-first-angular-app> ng serve --open
Initial chunk files | Names         |  Raw size
polyfills.js        | polyfills     |  83.60 kB | 
main.js             | main          |  22.09 kB | 
styles.css          | styles        |  95 bytes | 

                    | Initial total | 105.78 kB

Application bundle generation complete. [1.361 seconds]

Watch mode enabled. Watching for file changes...
  ➜  Local:   http://localhost:4200/
  ➜  press h + enter to show help

当你看到类似下面的页面被打开时,说明项目启动成功。

写一个"Hello World"

现在我们对项目中的文件做一些修改,更新页面。

  1. 首先,打开 my-first-angular-app/src/index.html
  2. 将 HTML 的 <title> 元素内容修改如下
html 复制代码
<title>Homes</title>
  1. 接下里,打开 my-first-angular-app/src/app/app.component.ts 文件,这是项目的根组件

  2. app.component.ts 文件里,在 @Component 定义中,修改 template 部分

diff 复制代码
- templateUrl: './app.component.html',
+ template: `<h1>Hello world!</h1>`,
  1. 同样在 app.component.ts 文件的 AppComponent 类定义中,更新 title 变量赋值部分
diff 复制代码
- title = 'my-first-angular-app';
+ title = 'homes';
  1. 终端终止 ng serve 执行,重新再执行一遍。

  2. 浏览器打开 localhost:4200 地址查看

修改成功,这就是 Angular 的"Hello World"程序啦。

创建 Home 组件

Angular 也是将页面看成是一个个组件(Component)构成的。

Angular 中,创建组件使用的是 ng generate component 命令,下面就来带大家手动创建一个 Home 组件感受一下。

  1. 进入 my-first-angular-app 目录
  2. 终端执行如下指令,创建一个新的 HomeComponent 组件
bash 复制代码
PS D:\learning\my-first-angular-app> ng generate component home --inline-template --skip-tests
CREATE src/app/home/home.component.ts (256 bytes)
CREATE src/app/home/home.component.css (0 bytes)

发现,在 src/app/ 下创建了一个 home 目录,包含 Home 组件内容。

--inline-template--skip-tests 是命令参数:表示使用的模板是内嵌的,还有忽略测试文件的创建。

  1. 进入 app.component.ts 文件。将 HomeComponent 组件引入进来
ts 复制代码
import { HomeComponent } from './home/home.component'
  1. 更新 @Component 中的 imports
ts 复制代码
imports: [
  HomeComponent,
],
  1. 更新 @Component 中的 template
ts 复制代码
template: `
  <main>
    <section class="content">
      <app-home></app-home>
    </section>
  </main>
`,
  1. 终端 ng serve 启动项目查看

看到这个效果,就说明组件添加成功了。

为 Home 组件添加功能

现在,我们为 Home 组件增加一个功能。

  1. 进入到 home.component.ts 文件
  2. 更新 @Component 的 template
ts 复制代码
template: `
  <section>
    <form>
      <input type="text" placeholder="Filter by city">
      <button class="primary" type="button">Search</button>
    </form>
  </section>
`,
  1. 接下来,打开 home.component.css 文件,为 Home 组件增加一些样式
css 复制代码
input[type="text"] {
  margin-right: 4px;
  width: 30%;
}

button {
  font: inherit;
}

.results {
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(400px, 400px));
  margin-top: 50px;
  justify-content: space-around;
}

我们为 <input><button> 元素简单设置了一些样式。.results 是查找结果的包装元素,先写上。

  1. 打开地址 http://localhost:4200/ 查看效果

创建 HousingLocation 组件

  1. 同样,进入 my-first-angular-app 目录
  2. 终端执行如下指令,创建一个新的 HousingLocationComponent 组件
bash 复制代码
PS D:\learning\my-first-angular-app> ng generate component housingLocation --inline-template --skip-tests
CREATE src/app/housing-location/housing-location.component.ts (303 bytes)
CREATE src/app/housing-location/housing-location.component.css (0 bytes)

发现,在 src/app/ 下创建了一个 housing-location 目录,包含 HousingLocation 组件内容。

  1. 进入 home.component.ts 文件。将 HousingLocation 组件引入进来
ts 复制代码
import { HousingLocationComponent } from '../housing-location/housing-location.component'
  1. 更新 @Component 中的 imports
ts 复制代码
imports: [
  HousingLocationComponent,
],
  1. 更新 @Component 中的 template,引入 <app-housing-location>
ts 复制代码
template: `
  <section>
    <form>
      <input type="text" placeholder="Filter by city">
      <button class="primary" type="button">Search</button>
    </form>
  </section>
  <section class="results">
    <app-housing-location></app-housing-location>
  </section>
  `,
  1. 打开 housing-location.component.css 文件,添加以下样式
css 复制代码
.listing {
  padding-bottom: 30px;
}

.listing-photo {
  height: 250px;
  width: 100%;
  object-fit: cover;
}

这块样式后面在实现时会用到。

  1. 终端 ng serve 启动项目查看

看到这个效果,就说明组件添加成功了。

创建接口类型

ng 还提供了 ng generate interface 命令支持,用于创建 TS 接口类型。

接下来,我们将为上一部创建的 HousingLocation 组件增加接口声明支持。

  1. 创建接口文件
bash 复制代码
ng generate interface housingLocation

这会创建 src/app/housing-location.ts 文件。

  1. housing-location.ts 文件中,添加如下的类型声明
ts 复制代码
export interface HousingLocation {
  id: number;
  name: string;
  city: string;
  state: string;
  photo: string;
  availableUnits: number;
  wifi: boolean;
  laundry: boolean;
}
  1. 进入 home.component.ts 文件,引入 HousingLocation 类型
ts 复制代码
import type { HousingLocation } from '../housing-location'
  1. 补充 export class HomeComponent {} 里的内容
ts 复制代码
export class HomeComponent {
  readonly baseUrl = 'https://angular.io/assets/images/tutorials/faa';

  housingLocation: HousingLocation = {
    id: 9999,
    name: 'Test Home',
    city: 'Test city',
    state: 'ST',
    photo: `${this.baseUrl}/example-house.jpg`,
    availableUnits: 99,
    wifi: true,
    laundry: false,
  };
}

housingLocation 变量使用了 HousingLocation 指定数据结构。

  1. 执行 ng serve,项目成功启动,没有报错。

为组件增加输入参数

在之前的章节里,我们使用了 @Component 修饰器来为组件定义一些元数据信息(metadata),而涉及到父子组件的数据共享时,就要用到 @Input 修饰器。

用 HousingLocationComponent 举例。

  1. 打开 src/app/housing-location/housing-location.component.ts 文件
  2. 增加 Input 修饰器以及 HousingLocation 类型的引入
ts 复制代码
import { Component, Input } from '@angular/core';
import { HousingLocation } from '../housing-location'
  1. 为 HousingLocationComponent 类增加 housingLocation 属性支持,并使用 @Input 修饰器修饰
ts 复制代码
export class HousingLocationComponent {
  @Input() housingLocation!: HousingLocation;
}

这一步表示 HousingLocationComponent 必须接收一个名为 housingLocation 的输入属性,这个属性是通过父组件传入的。

  1. 接下来进入 src/app/home/home.component.ts 文件

  2. 更新 @Component 修饰器 template 中引入 <app-housing-location> 的部分

ts 复制代码
<app-housing-location [housingLocation]="housingLocation"></app-housing-location>

[housingLocation]="housingLocation" 遵循 [attribute] = "value" 语法规则。

表示将 HousingLocation 组件的 housingLocation 属性与当前 Home 组件声明的属性 housingLocation 进行绑定。housingLocation 是在前一节中就初始化了。

在组件模板中使用输入参数

前一步我们在 HousingLocation 组件中声明的 housingLocation 属性可以直接在 template 中使用插入语法 {{}} 使用。

  1. 进入 src/app/housing-location/housing-location.component.ts 文件
  2. 更新 @Component 修饰器下的 template 内容
ts 复制代码
template: `
  <section class="listing">
    <img class="listing-photo" [src]="housingLocation.photo" alt="Exterior photo of {{housingLocation.name}}">
    <h2 class="listing-heading">{{ housingLocation.name }}</h2>
    <p class="listing-location">{{ housingLocation.city}}, {{housingLocation.state }}</p>
  </section>
  `,

这里,我们为 <img> 的 src 绑定了 housingLocation.photo 这个值,并使用插值语法分别将其他内容也提供出去。

  1. 执行 ng serve 启动项目,查看效果

成功!数据被正确渲染了。

使用 *ngFor 遍历列表数据

Angular 提供了一个 ngFor 指令用来遍历列表数据,其功能类似 JS 语言中的 for 循环。

  1. 为了展示列表功能,我们先修改 home.component.ts 文件,增加 housingLocationList 属性,承载列表数据。
ts 复制代码
export class HomeComponent {
  readonly baseUrl = 'https://angular.io/assets/images/tutorials/faa';

  housingLocationList: HousingLocation[] = [
    {
      id: 0,
      name: 'Acme Fresh Start Housing',
      city: 'Chicago',
      state: 'IL',
      photo: `${this.baseUrl}/bernard-hermant-CLKGGwIBTaY-unsplash.jpg`,
      availableUnits: 4,
      wifi: true,
      laundry: true
    },
    {
      id: 1,
      name: 'A113 Transitional Housing',
      city: 'Santa Monica',
      state: 'CA',
      photo: `${this.baseUrl}/brandon-griggs-wR11KBaB86U-unsplash.jpg`,
      availableUnits: 0,
      wifi: false,
      laundry: true
    },
  ]
}
  1. 接着在 home.component.ts 中使用 <app-housing-location> 的地方使用 ngFor 指令遍历 housingLocationList 这个列表
ts 复制代码
<app-housing-location 
  *ngFor="let housingLocation of housingLocationList"
  [housingLocation]="housingLocation"
></app-housing-location>

不过会看到报错。

这是因为 ngFor 指令是在 Angular 提供的 CommonModule 里的。需要额外引入。

  1. 在 home.component.ts 中引入 CommonModule 模块
ts 复制代码
import { CommonModule } from '@angular/common';
ts 复制代码
imports: [
  CommonModule,
  HousingLocationComponent
],
  1. 保存修改,打开 http://localhost:4200/ 查看效果

发现数据成功被遍历出来了。

Angular Service 与依赖注入

Angular Service 是一种将应用数据与业务逻辑分离的一种技术,方便在多个组件重用,是作为组件依赖存在的。

依赖注入(Dependency injection)则是一种管理组件依赖的算法,能限制其他组件可以访问到的服务。

创建 Angular Serivice

接下来,我们来学习创建 Angular Serivice。

  1. 首先,打开 my-first-angular-app 目录
  2. 接下来使用 ng generate service 命令来创建服务
bash 复制代码
PS D:\learning\my-first-angular-app> ng generate service housing --skip-tests
CREATE src/app/housing.service.ts (145 bytes)

创建了一个 src/app/housing.service.ts 文件。

  1. 接下来,复制下 home.component.ts 文件中的 housingLocationList 数据到 housing.service.ts 文件的 HousingService 类中
ts 复制代码
import { Injectable } from '@angular/core';
import { HousingLocation } from './housing-location';

@Injectable({
  providedIn: 'root'
})
export class HousingService {

  readonly baseUrl = 'https://angular.io/assets/images/tutorials/faa';

  housingLocationList: HousingLocation[] = [
    {
      id: 0,
      name: 'Acme Fresh Start Housing',
      city: 'Chicago',
      state: 'IL',
      photo: `${this.baseUrl}/bernard-hermant-CLKGGwIBTaY-unsplash.jpg`,
      availableUnits: 4,
      wifi: true,
      laundry: true
    },
    {
      id: 1,
      name: 'A113 Transitional Housing',
      city: 'Santa Monica',
      state: 'CA',
      photo: `${this.baseUrl}/brandon-griggs-wR11KBaB86U-unsplash.jpg`,
      availableUnits: 0,
      wifi: false,
      laundry: true
    }
  ];

  constructor() { }
}

注意,你会发现 HousingService 有一个 @Injectable 修饰器修饰。其实,每个服务都有,因为 Angular 中定义所有的服务都是可注入的(injectable)。

再添加 2 个获取数据的方法。

ts 复制代码
getAllHousingLocations(): HousingLocation[] {
  return this.housingLocationList;
}

getHousingLocationById(id: number): HousingLocation | undefined {
  return this.housingLocationList.find(housingLocation => housingLocation.id === id);
}

服务创建之后,就可以在组件中注入服务并使用了。

应用依赖注入

打开 home.component.ts 文件,我们将为其注入 HousingService 服务

  1. 从 @angular/core 中多引入一个 inject 方法
ts 复制代码
import { Component, inject } from '@angular/core';
  1. 再导入 housing.service。
ts 复制代码
import { HousingService } from '../housing.service';
  1. 将 HomeComponent 类下的 housingLocationList 置空([]

  2. 为 HomeComponent 增加 housingService 属性(对应 Housing 服务),通过 inject(HousingService) 方式实例化,再在 constructor 中调用服务上的方法初始化 housingLocationList 变量

ts 复制代码
housingLocationList: HousingLocation[] = [];
housingService: HousingService = inject(HousingService);

constructor() {
  this.housingLocationList = this.housingService.getAllHousingLocations();
}

这样做完后,查看效果。

发现跟之前的一样的效果。不同点在于,现在列表数据是通过服务的方式来获取的。

添加路由

路由是 SPA 项目页面中从一个组件导航到另一个组件的技术,能在不刷新整个页面的情况下,替换部分页面内容。

默认路由设置

通过 ng new 命令创建的项目,默认已经部署了路由支持,我们来看下。

  1. 打开 app.config.ts,这个文件对外导出了 appConfig 配置。
  2. appConfig 配置中,通过 @angular/router 中暴露的 provideRouter() 方法对 app.routes.ts 文件进行处理,作为 providers 对外提供。这里的 app.routes.ts 就是我们定义路由的地方
ts 复制代码
import type { Routes } from '@angular/router';

export const routes: Routes = [];
  1. appConfig 则在项目的入口文件 main.ts 中被使用
ts 复制代码
import { bootstrapApplication } from '@angular/platform-browser';
import { appConfig } from './app/app.config';
import { AppComponent } from './app/app.component';

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));

设置 AppComponent,使用路由配置

以上的配置,只是说明项目已经做了路由功能的部署,而具体页面内那块部分使用路由功能,还需要额外配置。因此,接下来我们将修改 app.component.ts,指定路由跳转的区域。

  1. 进入 src/app/app.component.ts,为其引入 RoutingModule,增加路由组件支持
ts 复制代码
import { RouterModule } from '@angular/router';

imports: [
  HomeComponent,
  RouterModule,
],
  1. 修改 template 属性,将 <app-home></app-home> 的地方替换成 <router-outlet>,这是切换路由时承载具体组件的占位组件
ts 复制代码
template: `
  <main>
    <a [routerLink]="['/']">
      <header class="brand-name">
        Home
      </header>
    </a>
    <section class="content">
      <router-outlet></router-outlet>
    </section>
  </main>
`,

查看效果。

因为我们还没有在 app.routes.ts 文件中定义路由,因此 <router-outlet> 并没有实际的组件与其对应,所以现在页面还是空白的。

定义跳转路由

接下来开始跳转路由的定义。

  1. 为了查看路由切换效果,我们还要再创建一个详情页组件
bash 复制代码
PS D:\learning\my-first-angular-app> ng generate component details --inline-template --skip-tests
CREATE src/app/details/details.component.ts (268 bytes)
CREATE src/app/details/details.component.css (0 bytes)
  1. 接下来进入 app.routes.ts,引入 HomeComponent 和 DetailsComponent,并设置到 routes 变量中
ts 复制代码
import { Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { DetailsComponent } from './details/details.component';

export const routes: Routes = [
  {
    path: '',
    component: HomeComponent,
    title: 'Home Page'
  },
  {
    path: 'details/:id',
    component: DetailsComponent,
    title: 'Details Page'
  }
];

path: '' 表示设置站点根路由,'details/:id' 则表示匹配类似 /details/xx 这种形式的路由。

  1. 执行 ng serve 启动项目

访问 http://localhost:4200/,看到的是 HomeComponent 渲染的效果。

访问 http://localhost:4200/details/1 看到的就是 DetailsComponent 渲染的效果。

进一步整合详情页

在定义详情页路由的时候,我们使用的是"details/:id",这里的 :id 是指路由参数 id,它的值是根据具体访问时的不同而不同。

当请求路由是"/details/1"时,id 值就是 1,当请求路由是"/details/2"时,id 值就是 2。

接下来,修改 details.component.ts 来获取路由参数 id。

获取路由参数 id

  1. 引入 ActivatedRoute 服务和注入服务所需的 inject() 方法
ts 复制代码
import { Component, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
  1. 注入 ActivatedRoute 服务,创建 route 实例。然后通过 this.route.snapshot.params['id'] 获得地址栏中的 id 参数值,并赋值给 housingLocationId 属性
ts 复制代码
export class DetailsComponent {
    route: ActivatedRoute = inject(ActivatedRoute);
    housingLocationId = -1;
    constructor() {
        this.housingLocationId = Number(this.route.snapshot.params['id']);
    }
}
  1. 接下里,修改 template,展示 housingLocationId 属性值
ts 复制代码
template: `<p>details works! {{ housingLocationId }}</p>`,
  1. 访问地址 http://localhost:4200/details/1,发现 id 参数成功获取到了

获取详情页内容

有了详情页的 id,就能从 HousingService 中获得某个 id 对应的详情信息了。我们来看看。

  1. detail.component.ts 中引入 HousingService 并注入,并根据 id 从 housingService 获取对应详情信息
ts 复制代码
import { HousingService } from '../housing.service';
import { HousingLocation } from '../housing-location';

export class DetailsComponent {

  route: ActivatedRoute = inject(ActivatedRoute);
  housingService = inject(HousingService);
  housingLocation: HousingLocation | undefined;

  constructor() {
    const housingLocationId = Number(this.route.snapshot.params['id']);
    this.housingLocation = this.housingService.getHousingLocationById(housingLocationId);
  }

}

housingLocation 就对应某个 id 详情信息。

  1. 修改 template,增加详情信息渲染
ts 复制代码
template: `
  <article>
    <img class="listing-photo" [src]="housingLocation?.photo"
      alt="Exterior photo of {{housingLocation?.name}}"/>
    <section class="listing-description">
      <h2 class="listing-heading">{{housingLocation?.name}}</h2>
      <p class="listing-location">{{housingLocation?.city}}, {{housingLocation?.state}}</p>
    </section>
    <section class="listing-features">
      <h2 class="section-heading">About this housing location</h2>
      <ul>
        <li>Units available: {{housingLocation?.availableUnits}}</li>
        <li>Does this location have wifi: {{housingLocation?.wifi}}</li>
        <li>Does this location have laundry: {{housingLocation?.laundry}}</li>
      </ul>
    </section>
  </article>
`,
  1. detail.component.css 增加一些样式
css 复制代码
.listing-photo {
  height: 600px;
  width: 50%;
  object-fit: cover;
  float: right;
}
  1. 查看效果。
  1. 点击左上角的"Home"会返回首页

这是通过 app.component.ts 的 routerLink 定义的: <a [routerLink]="['/']">。routerLink 的值是一个数组,定义路由 segment 信息,所有 segment 合在一起就是最终的跳转地址了。

表单提交

本节我们将增加表单提交功能。

  1. 进入 src/app/housing.service.ts 文件,为 HousingService 类增加 submitApplication() 方法
ts 复制代码
submitApplication(firstName: string, lastName: string, email: string) {
  console.log(`Homes application received: firstName: ${firstName}, lastName: ${lastName}, email: ${email}.`);
}
  1. 接下来进入 src/app/details/details.component.ts,引入 Angular Form 相关的类
ts 复制代码
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';

imports: [
  ReactiveFormsModule
],
  1. 接着在 DetailsComponent 类中在 constructor() 之前增加一个 applyForm 属性
ts 复制代码
applyForm = new FormGroup({
  firstName: new FormControl(''),
  lastName: new FormControl(''),
  email: new FormControl('')
});
  1. 然后在 DetailsComponent 类中在 constructor() 之后增加一个 submitApplication() 方法
ts 复制代码
submitApplication() {
  this.housingService.submitApplication(
    this.applyForm.value.firstName ?? '',
    this.applyForm.value.lastName ?? '',
    this.applyForm.value.email ?? ''
  );
}
  1. 接下来,我们将修改 details.component.ts 的 template,增加 <Form> 表单标签
ts 复制代码
template: `
  <article>
    <!-- ... -->
    <section class="listing-apply">
      <h2 class="section-heading">Apply now to live here</h2>
      <form [formGroup]="applyForm" (submit)="submitApplication()">
        <label for="first-name">First Name</label>
        <input id="first-name" type="text" formControlName="firstName">

        <label for="last-name">Last Name</label>
        <input id="last-name" type="text" formControlName="lastName">

        <label for="email">Email</label>
        <input id="email" type="email" formControlName="email">
        <button type="submit" class="primary">Apply now</button>
      </form>
    </section>
  </article>
`,

我们将 applyForm 绑定到 <form> 的 formGroup 属性,每个 <input> 通过 formControlName 为 applyForm 收集数据。再使用 (submit)="submitApplication()" 指定提交表单时的处理函数。

  1. 查看效果,发现调用成功

增加搜索功能

我们再为首页增加搜索功能。

  1. 进入 src/app/home/home.component.ts,为 HomeComponent 类增加 filteredLocationList 属性
ts 复制代码
filteredLocationList: HousingLocation[] = [];
  1. 然后在 constructor() 中,先讲 housingLocationList 设置给 filteredLocationList
ts 复制代码
constructor() {
  this.housingLocationList = this.housingService.getAllHousingLocations();
  this.filteredLocationList = this.housingLocationList;
}
  1. 再更新 template,为 <input> 增加模板变量 #filter
ts 复制代码
<input type="text" placeholder="Filter by city" #filter>
  1. 接着为"Search"按钮增加事件处理函数
ts 复制代码
<button class="primary" type="button" (click)="filterResults(filter.value)">Search</button>
  1. ngFor 指令遍历的对象也改成 filteredLocationList
ts 复制代码
<app-housing-location *ngFor="let housingLocation of filteredLocationList" [housingLocation]="housingLocation"></app-housing-location>
  1. 在 HomeComponent 类实现 filterResults() 方法
ts 复制代码
filterResults(text: string) {
  if (!text) {
    this.filteredLocationList = this.housingLocationList;
    return;
  }

  this.filteredLocationList = this.housingLocationList.filter(
    housingLocation => housingLocation?.city.toLowerCase().includes(text.toLowerCase())
  );
}
  1. 查看效果。输入框输入"chi",点击按钮,正确输出了结果

增加 HTTP 请求

最后,我们将启动一个 JSON 服务,提供数据列表的请求支持,在 housing-service.ts 使用。

启动 JSON 服务

  1. 首先安装 json-server
ts 复制代码
npm install -g json-server
  1. 再在项目根目录下创建一个 db.json 文件
ts 复制代码
{
  "locations": [
    {
    "id": 0,
    "name": "Acme Fresh Start Housing",
    "city": "Chicago",
    "state": "IL",
    "photo": "https://angular.io/assets/images/tutorials/faa/bernard-hermant-CLKGGwIBTaY-unsplash.jpg",
    "availableUnits": 4,
    "wifi": true,
    "laundry": true
    },
    {
    "id": 1,
    "name": "A113 Transitional Housing",
    "city": "Santa Monica",
    "state": "CA",
    "photo": "https://angular.io/assets/images/tutorials/faa/brandon-griggs-wR11KBaB86U-unsplash.jpg",
    "availableUnits": 0,
    "wifi": false,
    "laundry": true
    }
  ]
}
  1. 命令行执行下面指令,启动服务
ts 复制代码
json-server --watch db.json
  1. 访问 http://localhost:3000/locations,查看响应数据

更新 Service 接入 web server

  1. 进入 src/app/housing.service.ts 文件,移除 housingLocationList 属性
  2. 增加 url 属性
ts 复制代码
url = 'http://localhost:3000/locations';
  1. 更新 getAllHousingLocations() 方法实现
ts 复制代码
async getAllHousingLocations(): Promise<HousingLocation[]> {
  const data = await fetch(this.url);
  return await data.json() ?? [];
}
  1. 更新 getHousingLocationsById() 方法实现
ts 复制代码
async getHousingLocationById(id: number): Promise<HousingLocation | undefined> {
  const data = await fetch(`${this.url}/${id}`);
  return await data.json() ?? {};
}
  1. 进入 src/app/home/home.component.ts 文件,更新 constructor(),使用异步版本的 getAllHousingLocations()
ts 复制代码
constructor() {
  this.housingService.getAllHousingLocations().then((housingLocationList: HousingLocation[]) => {
    this.housingLocationList = housingLocationList;
    this.filteredLocationList = housingLocationList;
  });
}
  1. 进入 src/app/details/details.component.ts 文件,更新 constructor(),使用异步版本的 getHousingLocationById()
ts 复制代码
constructor() {
  const housingLocationId = Number(this.route.snapshot.params['id']);
  this.housingService.getHousingLocationById(housingLocationId).then(housingLocation => {
    this.housingLocation = housingLocation;
  });
}
  1. 保存后,浏览器查看结果

数据仍旧能够正常展示。

至此,我们就完成了一个简单的 Angular 程序。

总结

本文我们实现了一个具备建议搜索和列表展示功能的应用,从中学习了 Angular CLI 工具的使用以及一些概念,比如组件、接口、属性绑定、ngFor 指令、服务(涉及依赖注入)、路由、HTTP 请求等。

当然,以上只是带大家进行一次快速上手。如果你想要真正理解 Angular 的涉及理念和几大概念,就需要阅读官方文档的《理解 Angular》部分的内容了。

在理解了 Angular 设计思想之后,继续阅读《开发者指南》 详细了解 Angular 中每个技术点的使用。期间,还有 2 个教程: Tour of Heroestemplate-driven form,可以穿插学习,加深对 Angular 的理解。

总之,Angular 拥有一个很庞大的生态,所以完全掌握是需要一些时间的,切勿急躁。

好了。本文内容就先介绍到这里了,感谢你的阅读,再见。

相关推荐
蟾宫曲4 小时前
在 Vue3 项目中实现计时器组件的使用(Vite+Vue3+Node+npm+Element-plus,附测试代码)
前端·npm·vue3·vite·element-plus·计时器
秋雨凉人心4 小时前
简单发布一个npm包
前端·javascript·webpack·npm·node.js
liuxin334455664 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
qq13267029404 小时前
运行Zr.Admin项目(前端)
前端·vue2·zradmin前端·zradmin vue·运行zradmin·vue2版本zradmin
魏时烟5 小时前
css文字折行以及双端对齐实现方式
前端·css
哥谭居民00016 小时前
将一个组件的propName属性与父组件中的variable变量进行双向绑定的vue3(组件传值)
javascript·vue.js·typescript·npm·node.js·css3
踢足球的,程序猿6 小时前
Android native+html5的混合开发
javascript
2401_882726486 小时前
低代码配置式组态软件-BY组态
前端·物联网·低代码·前端框架·编辑器·web
web130933203986 小时前
ctfshow-web入门-文件包含(web82-web86)条件竞争实现session会话文件包含
前端·github
胡西风_foxww6 小时前
【ES6复习笔记】迭代器(10)
前端·笔记·迭代器·es6·iterator