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 拥有一个很庞大的生态,所以完全掌握是需要一些时间的,切勿急躁。

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

相关推荐
wearegogog12316 小时前
基于 MATLAB 的卡尔曼滤波器实现,用于消除噪声并估算信号
前端·算法·matlab
Drawing stars16 小时前
JAVA后端 前端 大模型应用 学习路线
java·前端·学习
品克缤16 小时前
Element UI MessageBox 增加第三个按钮(DOM Hack 方案)
前端·javascript·vue.js
小二·16 小时前
Python Web 开发进阶实战:性能压测与调优 —— Locust + Prometheus + Grafana 构建高并发可观测系统
前端·python·prometheus
小沐°16 小时前
vue-设置不同环境的打包和运行
前端·javascript·vue.js
qq_4198540517 小时前
CSS动效
前端·javascript·css
烛阴17 小时前
3D字体TextGeometry
前端·webgl·three.js
桜吹雪17 小时前
markstream-vue实战踩坑笔记
前端
南村群童欺我老无力.18 小时前
Flutter应用鸿蒙迁移实战:性能优化与渐进式迁移指南
javascript·flutter·ci/cd·华为·性能优化·typescript·harmonyos
C_心欲无痕18 小时前
nginx - 实现域名跳转的几种方式
运维·前端·nginx