0
点赞
收藏
分享

微信扫一扫

【Angular】161-Angular6入门项目(二)

皮皮球场 2022-11-29 阅读 204


本文目录

一、项目起步

二、编写路由组件

三、编写页面组件

  • 1.编写单一组件
  • 2.模拟数据
  • 3.编写主从组件

四、编写服务

  • 1.为什么需要服务
  • 2.编写服务

五、引入RxJS

  • 1.关于RxJS
  • 2.引入RxJS
  • 3.改造数据获取方式

六、改造组件

  • 1.添加历史记录组件
  • 2.添加和删除历史记录

七、HTTP改造

  • 1.引入HTTP
  • 2.通过HTTP请求数据
  • 3.通过HTTP修改数据
  • 4.通过HTTP增加数据
  • 5.通过HTTP删除数据
  • 6.通过HTTP查找数据

八、结语


这个入门项目是我学习完Angular 英雄指南教程(https://angular.cn/tutorial)后,自己手写的一个练习项目,一步一步来,最终的项目源码可以原文链接查看,大佬们请指点啦。



三、编写页面组件

接下来开始编写页面组件,这里我们挑重点来写,一些布局的样式,后面可以看源码。

1.编写单一组件

我们首先写一个书本信息的组件,代码如下:

  1. <!-- index.component.html -->
  2. <div class="content">
  3. <div class="books_box">
  4. <!-- 单个课本 -->
  5. <div class="books_item" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
  6. <img class="cover" src="https://img3.doubanio.com/view/subject/m/public/s29988481.jpg">
  7. <div class="title"><a>像火焰像灰烬</a></div>
  8. <div class="author">程姬</div>
  9. </div>
  10. </div>
  11. </div>

知识点

*ngFor​ 是一个 Angular 的复写器(repeater)指令,就像angular1中的 ​ng-for​和vuejs中的 ​v-for​。 它会为列表中的每项数据复写它的宿主元素。

这时候可以看到页面变成下面这个样子:

【Angular】161-Angular6入门项目(二)_html

接下来我们要把写死在HTML上面的数据,抽到JS中:

现在先新建一个 ​books.ts​​文件来定义一个 ​Book​​类,并添加 ​id​​, ​url​​, ​title​​和 ​author​四个属性:

  1. // src/app/books.ts
  2. export class Book {
  3. id: number;
  4. url: string;
  5. title: string;
  6. author: string;
  7. }

然后回到 ​index.component.ts​​文件去引入它,并定义一个 ​books​​属性,使用导入进来的 ​Book​类作为类型:

  1. // index.component.ts
  2. import { Book } from '../books';
  3. export class IndexComponent implements OnInit {
  4. books: Book = {
  5. id: 1,
  6. url: 'https://img3.doubanio.com/view/subject/m/public/s29988481.jpg',
  7. title: '像火焰像灰烬',
  8. author: '程姬',
  9. }
  10. }

然后再改造前面的组件文件 ​index.component.html​:

  1. <!-- index.component.html -->
  2. <div class="books_item" *ngFor="let item of [1,2,3,4,5,6,7,8,9,10]">
  3. <img class="cover" src="{{books.url}}" alt="{{books.id}}">
  4. <div class="title">
  5. <a>{{books.title}}</a>
  6. </div>
  7. <div class="author">{{books.author}}</div>
  8. </div>

接着,我们再为每个课本添加一个点击事件,来实现点击封面图能查看大图的效果,现在 ​index.component.ts​​中定义一个 ​getDetailImage​​方法,并在 ​index.component.html​中绑定该方法:

  1. // index.component.ts
  2. export class IndexComponent implements OnInit {
  3. getDetailImage(books){
  4. alert(`正在查看id${books.id}的大图!`);
  5. }
  6. }

这边方法的具体实现,不写,不是本文重点。下面是增加点击事件的绑定:

  1. <!-- index.component.html -->
  2. <img class="cover" src="{{books.url}}" alt="{{books.id}}" (click)="getDetailImage(books)">

知识点
​​(click)​​是Angular用来绑定事件,它会让 Angular 监听这个 ​<img>​​ 元素的 ​click​​ 事件。 当用户点击 ​<img>​​ 时,Angular 就会执行表达式 ​getDetailImage(books)​。

再来,我们引入前面学到的路由链接指令来改造HTML:

  1. <!-- index.component.html -->
  2. <a routerLink="/detail/{{books.id}}">{{books.title}}</a>

这时候,我们在点击书本的标题,发现页面跳转到URL地址为 ​http://localhost:4200/detail/1​的页面,这就说明,我们页面的路由跳转也成功了~

改造完成后,可以看到,页面显示的还是一样,接下来我们先这样放着,因为我们后面会进行数据模拟,和模拟服务器请求。

我们就这样写好第一个单一组件,并且数据是从JS中读取的。

2.模拟数据

这时候为了方便后面数据渲染,我们这里需要模拟一些本地数据,我们创建一个本地 ​mock-books.ts​文件来存放模拟的数据:

  1. // app/mock-books.ts
  2. import { Books } from './books';
  3. export const BookList: Books[] = [
  4. {
  5. id: 1,
  6. url: 'https://img3.doubanio.com/view/subject/m/public/s29988481.jpg',
  7. title: '像火焰像灰烬',
  8. author: '程姬',
  9. },
  10. // 省略其他9条
  11. ]

然后在 ​index.component.ts​​中导入模拟的数据,并将原有的 ​books​​值修改成导入的模拟数据 ​BookList​:

  1. // index.component.ts
  2. import { BookList } from '../mock-books';
  3. books = BookList;

并将原本的 ​*ngFor​中修改成这样,绑定真正的数据:

  1. <!-- index.component.html -->
  2. <div class="books_item" *ngFor="let item of books">
  3. <img class="cover" src="{{item.url}}" alt="{{item.id}}">
  4. <div class="title">
  5. <a>{{item.title}}</a>
  6. </div>
  7. <div class="author">{{item.author}}</div>
  8. </div>

3.编写主从组件

当我们写完一个单一组件后,我们会发现,如果我们把每个组件都写到同一个HTML文件中,这是很糟糕的事情,这样做有缺点:

  • 代码复用性差;(导致每次相同功能要重新写)
  • 代码难维护;(因为一个文件会非常长)
  • 影响性能;(打开每个页面都要重复加载很多)

为了解决这个问题,我们这里就要开始使用真正的组件化思维,将通用常用组件抽离出来,通过参数传递来控制组件的不同业务形态。
这便是我们接下来要写的主从组件。

思考一下,我们这里现在能抽成组件作为公共代码的,就是这个单个书本的内容,因为每个书本的内容都一致,只是里面数据的差异,于是我们再新建一个组件:

  1. ng g component books

并将前面 ​index.component.html​​中关于课本的代码剪切到 ​books.component.html​​中来,然后删除掉 ​*ngFor​​的内容,并将原本本地的变量 ​books​​替换成 ​list​,这个变量我们等会会取到:

  1. <!-- books.component.html -->
  2. <div class="books_item">
  3. <img class="cover" src="{{list.url}}" alt="{{list.id}}" (click)="getDetailImage(list)">
  4. <div class="title">
  5. <a routerLink="/detail/{{list.id}}">{{list.title}}</a>
  6. </div>
  7. <div class="author">{{list.author}}</div>
  8. </div>

再将这个组件,引用到它的父组件中,这里是要引用到 ​index.component.html​​的组件中,并将前面的 ​*ngFor​​再次传入 ​<app-books>​:

  1. <div class="content">
  2. <div class="books_box">
  3. <app-books *ngFor="let item of books"></app-books>
  4. </div>
  5. </div>

接下来要做的就是获取到 ​list​​变量的值,显然这个值是要从外面组件传进来的,我们需要在 ​books.component.ts​​引入前面定义的 ​Books​​类 和 ​@Input()装饰器​​,还要添加一个带有 ​@Input()装饰器​​的 ​list​​ 属性,另外还要记得将 ​getDetailImage​方法也剪切过来:

  1. // books.component.ts
  2. import { Component, OnInit, Input } from '@angular/core';
  3. import { Books } from '../books';

  4. export class BooksComponent implements OnInit {
  5. @Input() list: Books;
  6. constructor() { }
  7. ngOnInit() {}
  8. getDetailImage(books){
  9. alert(`正在查看id${books.id}的大图!`);
  10. }
  11. }

@Input()装饰器​介绍具体可以查看 手册

我们要获取的 ​list​​ 属性必须是一个带有 ​@Input()​​装饰器的输入属性,因为外部的 ​IndexComponent​组件将会绑定到它。就像这样:

  1. <app-books *ngFor="let list of books" [list]="item"></app-books>

知识点
​​[list]="item"​​ 是 ​Angular​ 的属性绑定语法。这是一种单向数据绑定。从 ​IndexComponent​​ 的 ​item​​属性绑定到目标元素的 ​list​​ 属性,并映射到了 ​BooksComponent​​ 的 ​list​ 属性。

做到这里,我们已经将 ​BooksComponent​​作为 ​IndexComponent​的子组件来引用了,在实际开发过程中,这样的父子组件关系,会用的非常多。

写到这里,看看我们项目,还是一样正常在运行,只是现在项目中组件分工更加明确了。

现在的效果图:

【Angular】161-Angular6入门项目(二)_点击事件_02

【Angular】161-Angular6入门项目(二)_数据_03


举报

相关推荐

0 条评论