项目目录介绍
编写Hello world
- 在app文件夹下,新建一个组件文件,文件名为hello-world.component.ts
从上图片中,我们可以得知组件的组成有以下三部分组成
-
类 (类名的命名是根据组件的文件名来决定的,首字母大写的驼峰命名方式)
-
装饰器@component, 需要从'@angular/core'中导入,其作用是把某个类标记为Angular组件,并为他配置一些元数据,目前这里只涉及到3个元数据,其中
selector也称作是选择器,我们可以把他理解成我们自定义组件的名字,一般他的命名也是app-组件文件的名字,更多的元数据应用可以参照官网。 -
HTML模板,就是template。
- 上边已经提到,组件必须在模块中声明才可以正常使用,所以我在根模块声明一下
- 我们将定义好的组件在app的html中引用一下
组件中值的传递
子传父
// app-outside-introduction是app.component的子组件,现在通过这个组件来学习一下父子传值
// outside-introduction.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-outside-introduction',
templateUrl: './outside-introduction.component.html',
styleUrls: ['./outside-introduction.component.scss']
})
export class OutsideIntroductionComponent {
// @Input()是专门用来实现传值的,需要提前在'@angular/core引入
// 这句声明,表示希望在父组件引入子组件的html页面中,从父组件中传入一个值给到showNumber
@Input() public showNumber: number;
}
// outside-introduction.component.html
<div>显示父组件传进来的值{{showNumber}}</div>
// 父组件app.component.html
<div>父组件中的值:{{defaultNum}}</div>
<app-outside-introduction [showNumber]="defaultNum"></app-outside-introduction>
// 父组件app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
public defaultNum = 5;
}
父传子
子组件向父组件传值,通过事件的形式来实现
// 子组件
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-outside-introduction',
templateUrl: './outside-introduction.component.html',
styleUrls: ['./outside-introduction.component.scss']
})
export class OutsideIntroductionComponent {
@Input() public showNumber: number;
// 下边的逻辑主要实现自组价向父组件emit一个值
@Output() public curCountChange = new EventEmitter<number>();
public curCount = 1;
public addCount(): void {
this.curCount++;
this.curCountChange.emit(this.curCount);
}
}
// 父组件
// 这里的事件名curCountChange必须和子组件定义@Output()的名字是一样的,=后边的方法名可以自己随意定义
// `$event`是子组件传过来的值
<app-outside-introduction [showNumber]="defaultNum" (curCountChange)="handlCurCountChange($event)"></app-outside-introduction>
public handlCurCountChange(value: number): void {
// 这里的value就是子组件传过来的值
this.valueFromChild = value;
}
-
@Output()- 一个装饰器函数,它把该属性标记为数据从子组件进入父组件的一种途径 -
curCountChange- 这个@Output()的名字 -
EventEmitter<number>- 这个@Output()的类型,就是子组件传给父组件的数据类型 -
new EventEmitter<number>()- 使用 Angular 来创建一个新的事件发射器,它发出的数据是number类型的。 -
curCountChange.emit()- 通过emit方法来向父组件传递值 最终父组件通过事件的形式接受子组件穿过来的值
组件的生命周期
Angular组件中生命周期共有九个,常用的有三到四个
路由
1.创建路由
import { NgModule } from '@angular/core';
// 引入路由模块 RouterModule和 Routes
import { Routes, RouterModule } from '@angular/router';
// 引入在不同URL下,需要展示的组件
import { GoodsListComponent } from './goods-list/goods-list.component';
import { PersonalCenterComponent } from './personal-center/personal-center.component';
// 配置的路由数组
const routes: Routes = [
{
path: 'goodsList', // 定义路由名称
component: GoodsListComponent, // 指定显示的那个组件
},
{
path: 'personalCenter', // 定义路由名称
component: PersonalCenterComponent, // 指定显示的那个组件
}
];
@NgModule({
// forRoot() 方法会创建一个 NgModule,其中包含所有指令、给定的路由以及 Router 服务本身。
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule {}
- 在app.module.ts中导入AppRoutingModule
import { AppRoutingModule } from './app-routing.module';
- 在app.component.html中把这些路由添加进来,以便控制导航的展示
<div class="route-change-container">
<a routerLink="/goodsList">切换到商品列表组件</a> <!--routerLink将你定义的路由连接到模板文件中-->
<a routerLink="/personalCenter">切换到个人中心组件</a>
</div>
<router-outlet></router-outlet> <!--此指令通过路由来动态加载组件-->
ActivatedRoute
用于获取路由信息
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router'; // ① 先引入ActivatedRoute
@Component({
selector: 'app-goods-list',
templateUrl: './goods-list.component.html',
styleUrls: ['./goods-list.component.scss']
})
export class GoodsListComponent implements OnInit {
constructor(
private route: ActivatedRoute, //依赖注入这个服务
) {}
// 在初始化的生命周期中去获取url的路由信息
public ngOnInit(): void {
// 第一种获取参数的方式
const params = this.route.snapshot.params;
// 第二种获取参数的方式
this.route.params.subscribe(params => {
console.log(params);
});
}
}
Router
是一个提供导航和操纵URL提供导航和操纵URL的模块,使用前需要引入
- navigate() 该方法支持的参数类型和routerLink指令一样,所以他们的作用也是一样的;
- navigateByUrl() 该方法支持绝对路由;
路由传参俩种形式
- params (是/:id 动态路由)
- queryParams(是?id=xx 形式)
路由传参三种方法
- routerLink 单一参数
<a [routerLink]="['/goodsList', id]" routerLinkActive="active-class">切换到商品列表组件</a>
// 其中/goodsListl是我设置的路由path,id是需要传递的参数
// 多个参数的时候,也可以用这种形式,只不过看起来不够直观,所以不推荐多个参数的时候也用这种方法
多个参数
<a [routerLink]="['/personalCenter']" [queryParams]="{name: 'zs', age: 16}">切换到个人中心组件</a>
// 参数的格式可以自行组织成各种object
- router.navigate 单一参数
public goToGoodsListPage(): void {
// 第一种方式
this._router.navigate([`/goodsList/${this.id}`]);
// 第二种方式 与第一种方式达到相同的效果
this._router.navigate(['/goodsList', this.id]);
}
// html中调用这个方法,等同于使用a标签的routerLink属性
<button (click)="goToGoodsListPage()">切换到商品列表组件</button>
多个参数
public goToPersonalCenterPage(): void {
this._router.navigate(['/personalCenter'], {queryParams:{name: 'zs', age: 16}});
}
// html中调用
<button (click)="goToPersonalCenterPage()">切换到个人中心组件</button>
- router.navigateByUrl
// 传的第一个参数是数组的形式,而navigate的第一个参数是数组的方式
// 他的传参目前是拼接在url上边的
public goToPersonalCenterPage(): void {
this._router.navigateByUrl(`/personalCenter?name=zs&age=16`);
}
在路由中接收参数的2种方式
- 接收params类型的参数
import { ActivatedRoute } from '@angular/router';
constructor(
private _route: ActivatedRoute,
) {}
public ngOnInit(): void {
// 第一种只获取初始值方式
const param = this.route.snapshot.params;
// 第二种动态获取方式
this.route.params.subscribe(params => {
console.log(params);
});
}
- 接收queryParams类型的参数
import { ActivatedRoute } from '@angular/router';
constructor(
private _route: ActivatedRoute,
) {}
public ngOnInit(): void {
// 第一种只获取初始值方式
const queryParam = this.route.snapshot.queryParams;
// 第二种动态获取方式
this.route.queryParams.subscribe(params => {
console.log(params);
});
}
响应式表单
提供对底层表单对象模型底层表单对象模型}底层表单对象模型直接、显式的访问。它们与模板驱动表单相比,更加健壮,它们的可扩展性、可复用性和可测试性都更高。而且控件更新的效率更高效率更高效率更高,因为FormControl 的实例总会返回一个新值,而不会更新现有的数据模型,如果表单是你的应用程序的关键部分,或者可扩展性很强,那就使用响应式表单
- 在模块文件中引入响应式表单模块
import { ReactiveFormsModule } from '@angular/forms';
- 在组件中引入表单组
import { FormGroup, FormControl } from '@angular/forms';
- 创建一个FormGroup实例,并把这个FormGroup模型关联到视图
this.profileForm = new FormGroup({
name: new FormControl(''),
password: new FormControl(''),
});
<form [formGroup]="profileForm" (ngSubmit)="submitForm(profileForm.value)">
<label for="name">First Name: </label>
<input id="name" type="text" formControlName="name"/>
<label for="password">Last Name: </label>
<input id="password" type="text" formControlName="password"/>
<button>提交</button>
</form>
HTTP
Angular给应用提供了一个HTTP客户端 API,也就是 @angular/common/http中的 HttpClient服务类。
使用HttpClient
- 在根模块下导入HttpClient
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
// 导入HttpClientModule
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
HttpClientModule,
],
exports: [],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
- 在服务类中依赖注入 (需要在服务类中通过HttpClient去进行通讯)
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable()
export class GoodsListService {
constructor(private http: HttpClient) { }
}
- 使用HttpClient返回的都是可观察对象(observable)类型的服务。因此我们还需要在服务类中导入RxJS 可观察对象可观察对象和可能会使用到的操作符操作符。
import { Observable } from 'rxjs';
import { pluck } from 'rxjs/operators'; // 此操作符是用来获取某个字段内容
常用的请求方式
- 从服务器请求数据 HttpClient.get()
// 在服务类中去封装和服务端通讯的方法
public getHttpResult(code: string, name: string): Observable<any> {
const url: string = ''; // 这是请求的地址
return this._http.get(url, { params: { code, name } });
}
- 发送数据到服务器 HttpClient.post()
public postHttpResult(body: any): Observable<any> {
const url: string = ''; // 这是请求的地址
return this._http.post(url, body);
}
错误处理
在调用接口的时候,当遇到接口请求失败或者报错的时候,前端需要做一些错误的提示信息展示,具体操作如下:
this._goodsListService.getHttpResult('12', 'zs')
.subscribe((res) => { // 由于httpClient返回的是observable,他必须被订阅之后才可以执行并返回结果
console.log(res);
}, (error) => { // 这里是接口报错的处理错误的地方
console.log(error);
});