一、父子组件传值篇
@Input() 和 @Output() 为子组件提供了一种与其父组件通信的方法。 @Input() 允许父组件更新子组件中的数据。相反,@Output() 允许子组件向父组件发送数据。
父组件向子组件传值—@Input
子组件或指令中的 @Input() 装饰器表示该属性可以从其父组件中获取值。
父组件 app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'my-app';
msg = '你好,子组件';
}
父组件 app.component.html
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
</div>
<app-child [item]="msg"></app-child>
<router-outlet></router-outlet>
子组件 child.component.ts
import { Component, OnInit, Input } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
// 子组件或指令中的 @Input() 装饰器表示该属性可以从其父组件中获取值。
@Input() item: string;
constructor() {
}
ngOnInit() {
}
}
子组件 child.component.html
<p>父组件传给子组件的值:{{item}}</p>
子组件向父组件传值—@Output、EventEmitter
子组件或指令中的 @Output() 装饰器允许数据从子组件传给父组件。子组件使用 @Output() 属性来引发事件,以通知父组件这一变化。为了引发事件,@Output()必须是EventEmitter类型,它是@angular/core中用来发出自定义事件的类。
子组件 child.component.ts
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
// 子组件或指令中的 @Input() 装饰器表示该属性可以从其父组件中获取值。
@Input() item: string;
// 子组件或指令中的 @Output() 装饰器允许数据从子组件传给父组件。
@Output() newItemEvent = new EventEmitter<string>();
constructor() {
}
ngOnInit() {
}
addNewItem(value: string) {
console.log(value);
this.newItemEvent.emit(value);
}
}
子组件 child.component.html
<p>父组件传给子组件的值:{{item}}</p>
<label>Add an item: <input #newItem></label>
<button (click)="addNewItem(newItem.value)">子组件向父组件中添加item</button>
父组件 app.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'my-app';
msg = '你好,子组件';
items = ['item1','item2', 'item3', 'item4'];
addItem(newItem: string) {
this.items.push(newItem);
}
}
父组件 app.component.html
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
</div>
<ul>
<li *ngFor="let item of items">{{item}}</li>
</ul>
<app-child [item]="msg" (newItemEvent)="addItem($event)"></app-child>
<router-outlet></router-outlet>
二、路由篇
项目中使用路由
要想在项目中使用路由,首先要创建一个带路由的应用项目。通过指令
ng new routing-app --routing可以创建一个附带路由的项目。
1、为路由添加组件
为了使用 Angular 的路由器,应用至少要有两个组件才能从一个导航到另一个。要使用 CLI 创建组件,请在命令行输入以下内容,其中 first 是组件的名称:
ng generate component first
为第二个组件重复这个步骤,但给它一个不同的名字。这里的新名字是 second。
ng generate component second
CLI 会自动添加 Component 后缀,所以如果在编写 first-component,那么其组件名就是 FirstComponentComponent。
2、导入这些新组件
要使用这些新组件,请把它们导入到该文件顶部的 AppRoutingModule 中,具体如下:
// 在app-routing.module.ts 文件中
import { FirstComponent } from './first/first.component';
import { SecondComponent } from './second/second.component';
3、定义一个基本路由
创建路由有三个基本的构建块。
把 AppRoutingModule 导入 AppModule 并把它添加到 imports 数组中。
Angular CLI 会为你执行这一步骤。但是,如果要手动创建应用或使用现存的非 CLI 应用,请验证导入和配置是否正确。
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module'; // CLI imports AppRoutingModule
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule // CLI adds AppRoutingModule to the AppModule's imports array
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
1、把 RouterModule 和 Routes 导入到你的路由模块中。
Angular CLI 会自动执行这一步骤。CLI 还为你的路由设置了Routes数组,并为@NgModule()配置了imports和exports数组。
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router'; // CLI imports router
const routes: Routes = []; // sets up routes constant where you define your routes
// configures NgModule imports and exports
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
2、在Routes数组中定义你的路由。
这个数组中的每个路由都是一个包含两个属性的 JavaScript 对象。第一个属性path定义了该路由的URL路径。第二个属性component定义了要让 Angular 用作相应路径的组件。
const routes: Routes = [
{ path: 'first-component', component: FirstComponent },
{ path: 'second-component', component: SecondComponent },
];
3、最后把这些路由添加到你的应用中。
现在你已经定义了路由,可以把它们添加到应用中了。首先,添加到这两个组件的链接。把要添加路由的链接赋值给routerLink属性。将属性的值设置为该组件,以便在用户点击各个链接时显示这个值。接下来,修改组件模板以包含<router-outlet>标签。该元素会通知 Angular,你可以用所选路由的组件更新应用的视图。
<!--app.component.html-->
<h1>Angular Router App</h1>
<!-- This nav gives you links to click, which tells the router which route to use (defined in the routes constant in AppRoutingModule) -->
<nav>
<ul>
<li><a routerLink="/first-component" routerLinkActive="active">First Component</a></li>
<li><a routerLink="/second-component" routerLinkActive="active">Second Component</a></li>
</ul>
</nav>
<!-- The routed views render in the <router-outlet>-->
<router-outlet></router-outlet>
路由顺序
路由的顺序很重要,因为Router在匹配路由时使用“先到先得”策略,所以应该在不那么具体的路由前面放置更具体的路由。首先列出静态路径的路由,然后是一个与默认路由匹配的空路径路由。通配符路由是最后一个,因为它匹配每一个URL,只有当其它路由都没有匹配时,Router才会选择它。
设置通配符路由
当用户试图导航到那些不存在的应用部件时,在正常的应用中应该能得到很好的处理。要在应用中添加此功能,需要设置通配符路由。当所请求的URL与任何路由器路径都不匹配时,Angular路由器就会选择这个路由。
要设置通配符路由,请在routes定义中添加以下代码。
{ path: '**', component: PageNotFoundComponent }
设置重定向
要设置重定向,请使用重定向源的path、要重定向目标的component和一个pathMatch值来配置路由,以告诉路由器该如何匹配URL。
const routes: Routes = [
{ path: 'first-component', component: FirstComponent },
{ path: 'second-component', component: SecondComponent },
{ path: '', redirectTo: '/first-component', pathMatch: 'full' }, // redirect to `first-component`
{ path: '**', component: PageNotFoundComponent }, // Wildcard route for a 404 page
];
路由传参
1、动态路由
1、首先在app-routing.module.ts文件中的routes数组中配置动态路由
{
path: 'first-component/:id',
component: FirstComponent,
}
2、在html页面中跳转传值
<!--动态路由传值-->
<a routerLink="/first-component/3" routerLinkActive="active">First Component</a>
<!--或者-->
<a [routerLink]="['/first-component/',3]">First Component</a>
2、query形式传参
在html页面中的routerLink的a标签中直接传参
<a routerLink="/second-component" [queryParams]="{name: '小笑残虹'}" routerLinkActive="active">
Second Component
</a>
获取路由参数信息
1、获取动态路由的值
假如我要在FirstComponent组件中获取动态路由传递的值,第一步:在first.component.ts文件中引入ActivatedRoute模块,作为route注入到构造器函数中。
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-first',
templateUrl: './first.component.html',
styleUrls: ['./first.component.scss']
})
export class FirstComponent implements OnInit {
constructor(private route: ActivatedRoute) {
}
}
然后就可以通过route.params.subscribe()方法获取到传递的值了。
ngOnInit() {
// 获取动态路由传值
console.log(this.route.params);
this.route.params.subscribe(data => {
console.log(data);
this.id = data.id
})
}
2、获取query形式传递过来的参数
假如我要在SecondComponent组件中获取query形式传递过来的值,第一步:在second.component.ts文件中引入ActivatedRoute模块,作为route注入到构造器函数中。
import {Component, OnInit} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
@Component({
selector: 'app-second',
templateUrl: './second.component.html',
styleUrls: ['./second.component.scss']
})
export class SecondComponent implements OnInit {
constructor(
private route: ActivatedRoute,
) {
}
}
然后就可以通过route.queryParams.subscribe()方法获取到传递的值了。
ngOnInit() {
// 获取params传值
this.route.queryParams.subscribe(params => {
console.log(params);
this.name = params['name'];
});
}
js跳转路由(编程式导航)
我要在
AppComponent组件中演示编程式导航,所以首先要在app.component.ts中引入Router模块,并且在constructor函数中进行初始化,引入NavigationExtras模块是为了进行query形式传参,NavigationExtras模块不需要在constructor构造器函数中初始化。
import { Router, NavigationExtras } from '@angular/router'
constructor(private router: Router) {}
1、js跳转普通路由
首先在页面上定义一个按钮用来模拟跳转
<button (click)="goHome()">js跳转路由</button>
通过router.navigate()方法进行跳转
// js跳转普通路由
goHome() {
this.router.navigate(['/home'])
}
2、js跳转动态路由
<!-- js动态路由跳转 -->
<button (click)="goToPath()">js动态路由跳转</button>
通过router.navigate()方法进行跳转
// js跳转动态路由
goToPath() {
// 路由跳转 适合普通路由和动态路由
this.router.navigate(['/first-component/', '123'])
}
3、js跳转路由query形式传参
注意:需要引入NavigationExtras模块
<button (click)="queryRoute()">js跳转路由query传参</button>
通过router.navigate()方法进行跳转
// js跳转路由query传参 (get传值)
queryRoute() {
let queryParams: NavigationExtras = {
queryParams: {
name: '王者荣耀'
}
}
this.router.navigate(['/second-component'], queryParams);
}
嵌套路由
随着你的应用变得越来越复杂,你可能要创建一些根组件之外的相对路由。这些嵌套路由类型称为子路由。这意味着你要为你的应用添加第二 ,因为它是AppComponent之外的另一个<router-outlet>。
在这个例子中,还有两个子组件,child-a和child-b。这里的FirstComponent有它自己的<nav>和AppComponent之外的第二<router-outlet>。
<h2>First Component</h2>
<nav>
<ul>
<li><a routerLink="child-a">Child A</a></li>
<li><a routerLink="child-b">Child B</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
子路由和其它路由一样,同时需要 path 和 component。唯一的区别是你要把子路由放在父路由的 children 数组中。
const routes: Routes = [
{
path: 'first-component',
component: FirstComponent, // this is the component with the <router-outlet> in the template
children: [
{
path: 'child-a', // child route path
component: ChildAComponent, // child route component that the router renders
},
{
path: 'child-b',
component: ChildBComponent, // another child route component that the router renders
},
],
},
];
三、HTTP客户端篇
使用HTTP与后端服务进行通信。大多数前端应用都要通过HTTP协议与服务器通讯,才能下载或上传数据并访问其它后端服务。Angular 给应用提供了一个简化的HTTP客户端 API,也就是@angular/common/http中的HttpClient服务类。
HTTP客户端服务提供了以下主要功能。
-
请求类型化响应对象的能力。
-
简化的错误处理。
-
各种特性的可测试性。
-
请求和响应的拦截机制。
服务器通讯的准备工作
1、要想使用HttpClient,就要先在app.module.ts中导入Angular的HttpClientModule。大多数应用都会在根模块AppModule中导入它。
// app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
BrowserModule,
// import HttpClientModule after BrowserModule.
HttpClientModule,
],
declarations: [
AppComponent,
],
bootstrap: [ AppComponent ]
})
export class AppModule {}
2、在用到的地方引入HttpClient并在构造器函数中声明。(我将要在NewsComponent组件中使用,所以在news.component.ts中引入HttpClient并在构造器函数中声明)
// news.component.ts
import {HttpClient} from "@angular/common/http";
constructor(public http:HttpClient) { }
get 请求数据
1、在news.component.html文件中定义一个按钮,来实现get方法请求服务器数据。
<button (click)="getData()">get请求</button>
2、在news.component.ts文件中实现getData()方法,get请求接口可以使用开源的https:httpbin.org/get
// get请求
getData() {
// https:httpbin.org/get
// https://httpbin.org/post
let api = 'http://a.itying.com/api/productlist';
this.http.get(api).subscribe((res: any) => {
console.log(res);
this.list = res.result;
})
}
post 提交数据
Angular5.x 以后get、post和服务器交互使用的是HttpClientModule模块。
1、在app.module.ts中引入HttpClientModule并注入
import {HttpClientModule} from '@angular/common/http';
imports: [ BrowserModule, HttpClientModule ]
2、在用到的地方引入HttpClient、HttpHeaders模块并在构造器函数中声明HttpClient。
在news.component.html文件中定义一个按钮,来实现post请求服务器数据。
<button (click)="doLogin()">post提交数据</button>
2、在news.component.ts文件中实现doLogin()方法,post请求接口可以使用开源的https:httpbin.org/post。
// post请求
doLogin() {
const httpOptions = {
headers: new HttpHeaders({"content-type": 'application/json'})
};
let url = 'https://httpbin.org/post';
this.http.post(url, {name: '小笑残虹', age: 18}, httpOptions).subscribe((res: any) => {
console.log(res);
this.postDate = res.json;
})
}
Jsonp 请求数据
1、在app.module.ts中引入HttpClientModule、HttpClientJsonpModule 并注入。
import {HttpClientModule,HttpClientJsonpModule} from '@angular/common/http';
imports: [ BrowserModule, HttpClientModule, HttpClientJsonpModule ]
2、在用到的地方引入HttpClient并在构造函数声明。
// news.component.ts
import {HttpClient} from "@angular/common/http";
constructor(public http:HttpClient) { }
<button (click)="getJsonp()">jsonp处理跨域</button>
// jsonp 跨域请求
getJsonp() {
/*
* http://a.itying.com/api/productlist?callback=xxx
* http://a.itying.com/api/productlist?cb=xxx
* */
let api = 'http://a.itying.com/api/productlist';
this.http.jsonp(api, 'callback').subscribe((res: any) => {
console.log(res);
this.list = res.result;
})
}
Angular 中使用第三方模块 axios 请求数据
1、安装 axios
npm install axios --save
2、用到的地方引入 axios
import axios from 'axios';
3、看axios文档使用
axios.get('/user?ID=12345')
.then(function (response){
// handle success console.log(response);
}).catch(function (error) {
// handle error console.log(error);
}).then(function () {
// always executed
});
下面,我们创建一个HttpService来使用axios,在这里可以对axios进行一些封装。
// service/http-service.service.ts
import {Injectable} from '@angular/core';
import axios from 'axios';
@Injectable({
providedIn: 'root'
})
export class HttpServiceService {
constructor() {
}
axiosGet(api) {
return new Promise((resolve, reject) => {
axios.get(api)
.then(res => {
resolve(res);
})
})
}
}
然后在app.module.ts中引入HttpServiceService服务并注入到providers数组中。
// app.module.ts
// 引入服务
import {HttpServiceService} from './service/http-service.service';
// 注入服务
providers: [HttpServiceService],
之后在NewsComponent组件中使用HttpServiceService服务
// news.component.ts
// 引入服务
import {HttpServiceService} from '../service/http-service.service'
// 初始化
constructor(public httpService: HttpServiceService) {}
<!--news.component.html-->
<button (click)="axiosGetData()">通过axios获取数据</button>
// news.component.ts
// axios get方法获取数据
axiosGetData() {
let api = 'http://a.itying.com/api/productlist';
this.httpService.axiosGet(api).then((res: any) => {
console.log(res);
this.list = res.data.result;
})
}