1.Angular介绍
Angular基于Typescript,和react、vue相比更适合于中大型企业级项目开发。
目前2019年12月25日最新版本为Angular9.x,根据官方介绍,Angular没几个月就会更新一个版本。
Angular2.x【包含】之后所有的版本用法都是一样的。
单页应用优点:
速度快
单页应用缺点:
不利于SEO优化
2.安装脚手架
npm install -g @angular/cli
ng v //查看是否安装成功
3.创建项目
ng new projectName
Would you like to add Angular routing? 是否增加Angular路由? 【推荐yes】
Whick stylesheet format would you like to use? CSS预处理器 【自己那个拿手用那个】
*如果要跳过脚手架 npm install的步骤
ng new projectName --skip-install
4.运行项目
ng serve --open //--open指自动打开浏览器
5.VS Code插件
下载量最大的那个就可以
6.Angular项目的目录结构
e2e 在e2e/下是端到端(End-to-End)测试文件夹
node_modules 项目所依赖的第三方模块
src 项目的所有文件全部需要放在src目录下
app 存放组件以及根模块(app.module.ts)
assets 静态资源文件夹
environments 为各个目标环境所准备的文件
browserslist Angular支持浏览器的配置文件【如果需要支持IE9-11,则把IE 9-11前面的not去掉】
favicon.ico 项目的图标
index.html html的入口文件
karma.conf.js karma的端对端单元测试配置文件
main.ts Angular项目的主入口
polyfills.ts 填充库(polyfill)能帮我们把这些不同点进行标准化,例如Angular中使用socket.io,Angular加载之前会首先加载这个文件
styles.css 全局样式,公共的css文件。
test.ts 单元测试的主要入口点
tsconfig.app.json TypeScript的配置文件
tsconfig.spec.json TypeScript的配置文件
tslint.json tslint的配置文件
typings.d.ts
.angular-cli.json Angular CLI的配置文件
.editorconfig 编译器的配置文件
.gitignore Git的忽略配置文件
angular.json Angular的配置文件
package.json npm配置文件
protractor.conf.js 给Protractor使用的端到端测试配置文件,当运行ng e2e的时候会用到它
READNE.md 项目的说明文档
tsconfig.json TypeScript的配置文件
tslint.json 给TSLint的配置文件,Lint功能可以帮你保持代码风格的统一。
7.需要牢记的几个文件
1.package.json
其中定义了项目名称,项目版本以及项目所需要的各种依赖。
2.src/app
存放组件、服务以及模块
3.src/assets
存放静态资源
4.src/index.html
html入口文件,正常不用管
5.src/styles.css
全局的css文件
8.Angular的核心文件
1.src/app/app.component.html、src/app/app.component.css、src/app/app.component.ts
根组件
/* 一个组件由业务逻辑[ts文件]以及html、css组成 */
//引入核心模块里面的Component
import { Component } from '@angular/core';
//@Component装饰器中传入一个对象
@Component({
selector: 'app-root', //定义组件的名称
templateUrl: './app.component.html', //组件所使用的html文件
styleUrls: ['./app.component.scss'] //组件所使用的css文件
})
//向外暴露组件
export class AppComponent {
title = 'coreqi-ng'; //定义一个属性
constructor(){ //构造函数
}
}
2.src/app/app.module.ts
根模块,告诉Angular如何组装应用
/* 这个文件是Angular根模块,告诉Angular如何组装应用 */
/* Angular 模块类描述应用的部件是如何组合在一起的。每个应用都至少有一个Angular模块,也就是根模块,用来引导
并运行应用。你可以为它取任何名称。常规名称是AppModule,也就是app.module.ts吻技安 */
//BrowserModule,浏览器解析的模块
import { BrowserModule } from '@angular/platform-browser';
//Angular的核心模块
import { NgModule } from '@angular/core';
//根组件
import { AppComponent } from './app.component';
/* @NgModule装饰器,@NgModule接收一个元数据对象,告诉Angular如何编译和启动应用 */
@NgModule({
declarations: [ //配置项目运行所需要的--组件
AppComponent
],
imports: [ //配置项目所需要的各种依赖【配置当前模块运行所依赖的其他--模块】
BrowserModule
],
providers: [], //配置项目所需要的--服务
bootstrap: [AppComponent] //指定应用的主视图(称为根组件),通过引导根组件 AppModule来启动应用,这里一般写的是根组件
})
//暴露根模块,根模块不需要导出任何东西,因为根模块不需要其他组件的导入,但是一定要暴露出来。
export class AppModule { }
9.组件
Angular是一个模块化、组件化的开发模式,所有的页面由组件组成。
1.使用Angular CLI工具创建组件【g是generate的简写】
ng g component 文件夹名称/组件名称 //文件夹名称可以省略
*如果是手动创建组件的话,创建完成后需要手动在根模块中注册。CLI创建的组件无需此操作【会自动在根模块中声明】
*组件在根模块中声明后,就可以在任意的组件html文件中使用了。
2.定义组件数据【属性】及数据【属性】绑定
定义
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {
public title="我是一个新闻组件" //定义组件数据
title="我是一个新闻组件" //可以省略public,默认就是public
username:string='fanqi' //在ts中推荐指定类型
public code:any=188 //推荐使用这种方式定义
public userinfo:object;
public html = '<h2>我是一段html</h2>'
constructor() {
this.userinfo = {
username:'fanqi',
}
}
ngOnInit(): void {
}
}
声明组件数据【属性】修饰符的说明:
修饰符 | 含义 | 说明 |
---|---|---|
public | 共有(默认) | 可以在这个类里面使用,也可以在类外面使用 |
protected | 保护类型 | 只有在当前类和它的子类里面可以访问 |
private | 私有 | 只有在当前类才可以访问这个属性 |
绑定
<p>新闻组件</p>
<h2>{{title}}</h2> <!--绑定-->
<div [title]="username"></div>
<span [innerHTML]='html'></span>
3.引入图片
<h1>引入图片</h1>
<img src="assets/images/01.png" alt="收藏"/> <!--引入本地静态资源文件夹图片-->
<img [src]="picUrl" alt="" /> <!--引入在属性中定义的图片地址-->
4.指令【略】
常见的例如 if for switch等等
5.管道【类似于过滤器,常用于日期转换】
{{today | data:'yyyy-MM-dd HH:mm ss'}}
自定义管道【略】
6.事件
<button (click)="run">
执行事件
</button>
<input type="text" (keydown)="keyDown($event)" /> <!--传入事件对象-->
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {
constructor() {
}
ngOnInit(): void {
}
run(){
console.log("事件触发了方法")
}
keyDown(e){
//ionic必须指定为any。
let dom:any=event.target;
dom.style.color="red"
}
}
7.双向数据绑定【只是针对于表单】
Model改变会影响视图,视图改变也会反向的影响Model
1.引入FormsModule模块
import { FormsModule } from '@angular/forms';
2.在根模块中注册
/* 这个文件是Angular根模块,告诉Angular如何组装应用 */
//BrowserModule,浏览器解析的模块
import { BrowserModule } from '@angular/platform-browser';
//Angular的核心模块
import { NgModule } from '@angular/core';
//根组件
import { AppComponent } from './app.component';
import { NewsComponent } from './components/news/news.component';
import { FormsModule } from '@angular/forms';
/* @NgModule装饰器,@NgModule接收一个元数据对象,告诉Angular如何编译和启动应用 */
@NgModule({
declarations: [ //配置项目运行所需要的组件
AppComponent, NewsComponent
],
imports: [ //配置项目所需要的各种依赖【配置当前模块运行所依赖的其他模块】
BrowserModule,
FormsModule
],
providers: [], //配置项目所需要的服务
bootstrap: [AppComponent] //指定应用的主视图(称为根组件),通过引导根组件 AppModule来启动应用,这里一般写的是根组件
})
//暴露根模块,根模块不需要导出任何东西,因为根模块不需要其他组件的导入
export class AppModule { }
3.使用
<input type="text" [(ngModel)]="inputValue" />
{{inputValue}}
10.服务
组件之间的方法是无法相互调用的。于是把公共的方法提取为服务。
服务和服务之间可以相互调用,组件和组件之间不能相互调用,但是可以父子组件间传值
1.通过脚手架创建服务
ng g service serviceName
ng g service folderName/serviceName
2.在根模块中注册服务
/* 这个文件是Angular根模块,告诉Angular如何组装应用 */
//BrowserModule,浏览器解析的模块
import { BrowserModule } from '@angular/platform-browser';
//Angular的核心模块
import { NgModule } from '@angular/core';
//根组件
import { AppComponent } from './app.component';
import { NewsComponent } from './components/news/news.component';
import { FormsModule } from '@angular/forms';
import { FormComponent } from './components/form/form.component';
//引入服务
import { StorageService } from './services/storage.service'
/* @NgModule装饰器,@NgModule接收一个元数据对象,告诉Angular如何编译和启动应用 */
@NgModule({
declarations: [ //配置项目运行所需要的组件
AppComponent, NewsComponent, FormComponent
],
imports: [ //配置项目所需要的各种依赖【配置当前模块运行所依赖的其他模块】
BrowserModule,
FormsModule
],
providers: [StorageService], //配置项目所需要的服务
bootstrap: [AppComponent] //指定应用的主视图(称为根组件),通过引导根组件 AppModule来启动应用,这里一般写的是根组件
})
//暴露根模块,根模块不需要导出任何东西,因为根模块不需要其他组件的导入
export class AppModule { }
3.在服务中声明方法
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class StorageService {
constructor() { }
get(){
return 'this is a service method';
}
}
4.在组件中引入服务方法
import { Component, OnInit } from '@angular/core';
//引入服务
import { StorageService } from '../../services/storage.service'
//可以使用服务,但是不推荐这种方式
//var storage = new StorageService();
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {
title="我是一个新闻组件"
//使用构造器注入
constructor(public storage:StorageService) {
let result = this.storage.get();
console.log(result);
}
ngOnInit(): void {
}
}
11.Angular中的dom操作
1.通过原生js
*备注内容 ngOnInit()–生命周期函数–组件和指令初始化完成,并不是真正的dom加载完成,获取不到dom节点
//视图加载完成以后触发的方法,建议把dom的操作放在这个里面
ngAfterViewInit(){
var boxDom:any=document.getElementById('box');
boxDom.style.color='red';
}
2.通过Angular提供的装饰器【ViewChild】
1.在组件的模板页创建dom节点
<div #mybox>
这是一个dom节点
</div>
2.在组件的逻辑中引入ViewChild
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core'; //引入ViewChild
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit,AfterViewInit{
//使用ViewChild装饰器获取dom节点
@ViewChild('mybox') myBox:ElementRef;
//@ViewChild('mybox') myBox:any;
constructor() {
}
ngAfterViewInit():void{
console.log(this.myBox.nativeElement);
this.myBox.nativeElement.style.width='100px';
}
ngOnInit(): void {
}
}
12.Angular父组件通过ViewChild调用子组件的方法
1.在父组件的模板中引入子组件
<app-header #header></app-header>
<div #myBox>
我是父组件
</div>
2.在父组件逻辑中调用子组件以及方法
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core'; //引入ViewChild
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit,AfterViewInit{
//使用ViewChild装饰器获取dom节点
@ViewChild('mybox') myBox:any;
//获取一个组件【你就把它当成一个dom节点】,这样我们就在父组件里面获取了子组件的实例
@ViewChild('header') header:any;
constructor() {
}
ngAfterViewInit():void{
console.log(this.myBox.nativeElement);
this.myBox.nativeElement.style.width='100px';
//调用子组件的方法,可以通过this.header获取子组件的实例
this.header.run();
}
ngOnInit(): void {
}
}
13.Angular组件通信
1.父子组件通信–子组件获取父组件【@input】
父组件不仅可以给子组件传递简单的数据,还可以把自己的方法以及整个父组件传给子组件。
1.父组件在调用子组件的时候在自定义属性中传入数据,也可以传入方法,也可以传入整个父组件【父组件实例】
<app-header [msg]="msg" [run]="run" [home]='this'></app-header>
2.子组件引入Input模块并通过@Input接收父组件传过来的数据
import { Component, OnInit, Input } from '@angular/core'; //引入Input模块
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit {
//接收父组件数据
@Input() msg:string
//接收父组件方法
@Input() run:any
//接收父组件实例
@Input() home:any
constructor() { }
ngOnInit(): void {
}
handleClick():void{
this.run();
//输出父组件数据
console.log(this.home.msg);
}
}
2.父子组件通信–父组件获取子组件【@ViewChild】
1.父组件在调用子组件时给子组件定义一个名称
<app-footer #footerChild></app-footer>
2.在父组件中通过@ViewChild获取子组件实例
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core'; //引入ViewChild
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit,AfterViewInit{
//使用ViewChild装饰器获取dom节点
@ViewChild('footerChild') footerChild:any;
constructor() {
}
ngAfterViewInit():void{
console.log(this.footerChild.nativeElement);
this.footerChild.nativeElement.style.width='100px';
//调用子组件的方法,可以通过this.header获取子组件的实例
this.footerChild.run();
}
ngOnInit(): void {
}
}
2.父子组件通信–通过事件驱动父组件获取子组件【@Output】
1.子组件引入Output和EventEmitter
import { Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
2.子组件中实例化EventEmitter
//用EventEmitter和output装饰器配合使用,<string>指定类型变量
@Output() private outer = new EventEmitter<string>();
3.子组件通过EventEmitter的对象实例广播数据
import { Component, OnInit, Input, Output, EventEmitter} from '@angular/core';
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class HeaderComponent implements OnInit{
//用EventEmitter和output装饰器配合使用,<string>指定类型变量
@Output() private outer = new EventEmitter<string>();
constructor() {
}
ngOnInit(): void {
}
sendParent(){
this.outer.emit('msg from child')
}
}
4.父组件调用子组件的时候,定义接收事件,outer就是子组件的EventEmitrrer对象outer
<app-header (outer)="runParent($event)"></app-header>
5.父组件接收到数据会调用自己的runParent方法,这个时候就能拿到子组件的数据
//接收子组件传递过来的数据
runParent(e){
console.log(e);
}
3.组件之间通信
1.通过服务
2.Localstorage
14.Angular生命周期
声明周期函数通俗的讲就是组件创建、组件更新、组件销毁时会触发的一系列方法。
当Angular使用构造函数新建一个组件或指令后,就会按下面得顺序在特定时刻调用这些声明周期钩子方法。
constructor | 构造函数中除了使用简单的值对局部变量进行初始化之外,什么都不应该做【非生命周期函数】 |
---|---|
ngOnChanges() | 当Angular(重新)设置数据绑定输入属性时相应。该方法接收当前和上一属性值的SimpleChanges对象,当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在ngOnInit()之前。父组件给子组件传值的时候以及父组件改变传值的数据的时候将会被触发。 |
ngOnInit()★ | 在Angular第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。在第一轮ngOnChanges()完成之后调用,只调用一次。使用ngOnInit()有两个原因:1.在构造函数之后马上执行复杂的初始化逻辑。2.在Angular设置完输入属性之后,对该组件进行准备。有经验的开发者会认同组件的构建应该很便宜和安全。一般用来做请求数据。 |
ngDoCheck() | 检测,并在发生Angular无法或不愿意自己检测的变化时作出反应。在每个Angular变更检测周期中调用,ngOnChanges()和ngOnInit()之后。可以做一些自定义操作,例如检测数据有没有改变,如果改变是一种操作,没有改变是另外一种操作。 |
ngAfterContentInit() | 当把内容投影进组件之后调用。第一次ngDoCheck()之后调用,只调用一次。组件渲染完成之后触发的生命周期函数 |
ngAfterContentChecked() | 每次完成被投影组件内容的变更检测之后调用。ngAfterContentInit()和每次ngDoCheck()之后调用。组件初始化完成之后可以自己定义一些自定义操作。 |
ngAfterViewInit()★ | 初始化完组件视图及其子视图之后调用。第一次ngAfterContentChecked()之后调用,只调用一次。视图加载完成之后触发,一般用于针对DOM的操作。 |
ngAfterViewChecked() | 每次做完组件视图和子视图的变更检测之后调用。ngAfterViewInit()和每次ngAfterContentChecked()之后调用。在视图加载完成之后做一些自定义的操作 |
ngOnDestroy()★ | 当Angular每次销毁指令/组件之前调用并清扫。在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。组件销毁时触发的生命周期函数。 |
监听生命周期时可以实现生命周期接口,也可以不实现。
*当数据变化时,触发以下生命周期函数:
ngDoCheck、ngAfterContentChecked、ngAfterViewChecked
*Init的生命周期函数只会执行一次,而Check类的声明周期函数将会在数据改变时触发。
*ngOnChanges()主要用在父子组件传值,父组件被当成子组件传值的时候它才会触发。
15.Rxjs异步数据流编程
Rxjs是ReactiveX编程理念的javascript版本,ReactiveX来自微软,它是一种针对异步数据流的编程,简单来说,它将一切数据,包括http请求,dom事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据并组合不同的操作符来轻松优雅的实现你所需要的功能。
RxJS是一种针对异步数据流的编程工具,或者叫响应式扩展编程;可不管如何解释RxJS其目标就是异步编程,Angular引入RxJS就是为了让异步可控、更简单。
RxJS里面提供了很多模块,最常用的有Observable和fromEvent。
目前最常见的异步编程的几种方式:
1.回调函数
2.事件监听/发布订阅
3.Promise
let promise = new Promise(resolve => {
setTimeout(() => {
resolve('---promise timeout---');
},2000);
});
promise.then(value => console.log(value));
4.Rxjs
import {Observable} from 'rxjs'; //Angular已经集成,不需要安装直接引用即可。
let stream = new Observable(observer => {
setTimeout(() => {
observer.next('observable timeout'); //成功的返回方式
//observer.error('数据'); //失败的返回方式
},2000);
});
stream.subscribe(value => console.log(value));
从上面例子可以看到RxJS和Promise的基本用法非常类似,除了一些关键词不同。Promise里面用的是then()和resolve(),而RxJS里面用的是next()和subscribe()。
其实Rxjs相比Promise要强大很多,比如Rxjs中可以中途撤回、Rxjs可以发射多个值、Rxjs提供了多种工具函数等等。
1.Rxjs unsubscribe取消订阅
Promise的创建之后动作是无法撤回的,而Observable不一样,Observable的动作可以通过unsubscribe()方法中途撤回,而且Observable在内部做了智能的处理。
Promise创建之后动作无法撤回
let promise = new Promise(resolve => {
setTimeout(() => {
resolve('---promise timeout ---');
},2000);
});
promise.then(value => console.log(value));
Rxjs可以通过unsubscribe()可以撤回subscribe的动作。
let stream = new Observable(observer => {
let timeout = setTimeout(() => {
clearTimeout(timeout);
observer.next('observable timeout');
},2000);
});
let disposable = stream.subscribe(value => console.log(value));
setTimeout(() => {
//取消执行
disposable.unsubscribe();
},1000);
2.Rxjs订阅后多次执行
如果我们想让异步里面的方法多次执行,这一点Promise是做不到的,对于Promise来说,最终结果要么resole(兑现)、要么reject(拒绝),而且都只能触发一次,如果在同一个Promise对象上多次调用resolve方法,则会抛出异常。
而Observable不一样,它可以不断地触发下一个值,就像next()这个方法的名字所暗示的那样。
let promise = new Promise(resolve => {
setInterval(() => {
resolve('---promise setInterval---';)
},2000);
});
//即使有定时器每2S执行一次,但最终只会执行一次。
promise.then(value => console.log(value));
Rxjs
let stream = new Observable<number>(observer => {
let count = 0;
setlnterval(() => {
observer.next(count++);
},1000);
});
stream.subscribe(value => console.log('Observable>'+value));
3.Angular6.x之前使用Rxjs的工具函数 map&filter
注:Angular6以后如果要使用以前的Rxjs方法必须安装rxjs-compat模块才可以使用map、filter方法。
angular6后官方使用的是RXJS6的新特性,所以官方给出了一个可以暂时延缓我们不需要修改rsjx代码的办法。
npm install rxjs-compat
import {Observable} from 'rxjs';
import 'rxjs/Rx';
let stream = new Observable<any>(observer => {
let count = 0;
setlnterval(() => {
observer.next(count++);
},1000);
});
stream.filter(val => val%2 == 0).subscribe(value => console.log("filter>" + value));
stream.map(value => {return value * value}).subscribe(value => console.log("map>" + value));
4.Angular6.x以后Rxjs6.x的变化以及使用
Rxjs的变化参考文档:http://bbs.itying.com/topic/5bfce189b110d80f905ae545
Rxjs6改变了包的结构,主要变化在import方式和operator上面以及使用pipe()
import {Observable} from 'rxjs';
import {map,filter} from 'rxjs/operators';
let stream = new Observable<any>(observer => {
let count = 0;
setlnterval(() => {
observer.next(count++);
},1000);
});
stream.pipe(filter(val => val%2 == 0)).subscribe(value => console.log("filter>" + value));
stream.pipe(filter(val => val%2 == 0),map(value => {return value * value})).subscribe(value => console.log("map>" + value));
5.Rxjs延迟执行
import {Observable,fromEvent} from 'rxjs';
import {map,filter,throttleTime} from 'rxjs/operators';
var button = document.querySelector('button');
fromEvent(button,'click').pipe(throttleTime(1000)).subscribe(() => console.log('Clicked'));
16.Angular中的数据交互
1.Angular get 请求数据
Angular5.x以后get、post和服务器交互使用的是HttpClientModule
模块
1.在app.module.ts中引入HttpClientModule并注入
import { HttpClientModule } from '@angular/common/http'
imports: [ //配置项目所需要的各种依赖【配置当前模块运行所依赖的其他模块】
BrowserModule,
HttpClientModule,
FormsModule //双向数据绑定
],
2.在用到的地方引入HttpClient并在构造函数中声明
import { HttpClient } from '@angular/common/http';
constructor(public http:HttpClient){ }
3.get 请求数据
var api = "http://a.itying.com/api/productlist";
this.http.get(api).subscribe(response => {
console.log(response);
});
2.Angular post请求数据
1.在app.module.ts中引入HttpClientModule并注入
import { HttpClientModule } from '@angular/common/http'
imports: [ //配置项目所需要的各种依赖【配置当前模块运行所依赖的其他模块】
BrowserModule,
HttpClientModule,
FormsModule //双向数据绑定
],
2.在用到的地方引入HttpClient、HttpHeaders并在构造函数中声明HttpClient
import {HttpClient,HttpHeaders} from '@angular/common/http';
constructor(public http:HttpClient){ }
3.post 提交数据
const httpOptions ={
headers:new HttpHeaders({
'Content-Type':'application/json',
})
};
var api = "http://127.0.0.1:3000/doLogin";
this.http.post(api,{username:'fanqi',age:'26'},httpOptions).subscribe(response => {
console.log(response);
});
3.Angular Jsonp请求数据【跨域】
Jsonp请求 服务器必须得支持Jsonp
1.在app.module.ts中引入HttpClientModule、HttpClientJsonpModule并注入
import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http'
imports: [ //配置项目所需要的各种依赖【配置当前模块运行所依赖的其他模块】
BrowserModule,
HttpClientModule,
HttpClientJsonpModule,
FormsModule //双向数据绑定
],
2.在用到的地方引入HttpClient并在构造函数声明
import { HttpClient } from '@angular/common/http';
constructor(public http:HttpClient){ }
3.jsonp请求数据
var api = "http://a.itying.com/api/productlist";
// http://a.itying.com/api/productlist?callback=xxx
this.http.jsonp(api,'callback').subscribe((response) => {
console.log(response);
})
4.Angular中使用第三方模块axios请求数据
1.安装axios
npm install axios -S
2.在用到得地方引入axios
import axios from 'axios';
3.使用
axios.get('/user?ID=12345').then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
17.Angular中的路由
路由就是根据不同的url组件,动态的让根组件挂载其他组件来实现一个单页面应用。
*如果使用ng new project
时选择了路由,则会:
1.自动创建app-routing.module.ts【路由配置模块】
2.在根模块中自动引入AppRoutingModule
模块
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module'; //
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule //
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
3.在根组件模板中多了以下标签
<router-outlet></router-outlet> <!--存放动态加载的组件-->
1.配置路由
//配置路由的模块
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
//引入组件
import { NewsComponent } from './components/news/news.component'
import { HomeComponent } from './components/home/home.component'
import { ProductComponent } from './components/product/product.component'
//在此处配置路由
const routes: Routes = [
{
path:'home',
component:HomeComponent,
},
{
path:'news',
component:NewsComponent,
},
{
path:'product',
component:ProductComponent,
},
//匹配不到路由的时候加载的组件 或者跳转的组件
{
path: '**', //表示任意的路由
redirectTo: 'home',
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
2.配置路由链接
<h1>
<a [routerLink]="['/home']">首页</a>
<a [routerLink]="['/news']">新闻</a>
<a [routerLink]="['/product']">商品列表</a>
</h1>
<router-outlet></router-outlet>
3.点中某个链接则处于选中状态
<h1>
<a [routerLink]="['/home']" routerLinkActive="router-link-active">首页</a> <!--如果当前链接是选中状态,则会自动加上router-link-active样式-->
<a [routerLink]="['/news']" routerLinkActive="router-link-active">新闻</a>
<a [routerLink]="['/product']" routerLinkActive="router-link-active">商品列表</a>
</h1>
<router-outlet></router-outlet>
.router-link-active{
color:red
}
4.路由跳转传值
1.链接get传值
<a [routerLink]="['/newsContent']" [queryParams]="{id:1,name:'fanqi'}">新闻详细</a>
2.在跳转的组件中获取值
import { ActivatedRoute } from '@angular/router';
constructor(public route:ActivatedRoute){ }
ngOnInit(){
this.route.queryParams.subscribe((data) => {
console.log(data);
})
}
5.动态路由
1.在路由配置里面配置
{
path: 'newsContent/:id',
component: NewsContentComponent,
}
2.动态路由传值
<a [routerLink]="['/newsContent/', id]">新闻详细</a>
3.获取动态路由传来的值
import { ActivatedRoute } from '@angular/router';
constructor(public route:ActivatedRoute){ }
ngOnInit(){
this.route.params.subscribe((data) => {
console.log(data);
})
}
6.动态路由的js跳转
1.引入模块
import { Router } from '@angular/router';
2.初始化
export class HomeComponent implements OnInit{
constructor(private router: Router){ }
ngOnInit(){ }
goNews(){
//this.router.navigate(['/news/',hero.id]);
//路由跳转 适合普通路由和动态路由
this.router.navigate(['/news']);
this.router.navigate(['/newsContent/','7'])
}
}
7.get传值路由的js跳转
1.引入NavigationExtras
import { Router, NavigationExtras } from '@angular/router'
2.定义一个goNewsContent方法执行跳转,用NavigationExtras配置传参
goNewsContent(){
let navigationExtras: NavigationExtras = {
queryParams: {'session_id':'123'},
fragment: 'anchor',
};
this.router.navigate(['/news'],navigationExtras);
}
8.父子路由【嵌套路由】
1.在路由配置文件中配置子路由
const routes:Routes = [
{
path:'home',
component: HomeComponent,
children:[
{
path: 'welcome',
component: WelcomeComponent,
},
{
path: 'setting',
component: SettingComponent,
},
{
path: '**',
redirectTo:'welcome',
}
],
}
]
2.在页面中配置
<div class="content">
<div class="left">
<a [routerLink]="['/home/welcome']">欢迎首页</a>
<br/>
<br/>
<a [routerLink]="['/home/setting']">系统设置</a>
</div>
<div class="right">
<router-outlet></router-outlet>
</div>
</div>
18.Angular中的模块
1.Angular内置模块
☆@angular/core Angular核心模块
☆@angular/common Angular通用模块
☆@angular/forms Angular表单模块
☆@angular/http Angular网络模块
☆…
2.Angular自定义模块
当我们项目比较小的时候可以不用自定义模块,但是当我们项目非常庞大的时候把所有的组件都挂载到根模块中不是特别合适【会导致页面加载比较慢】,所以这个时候我们就可以自定义模块来组织我们的项目,并且通过Angular自定义模块可以实现路由的懒加载。
将功能类似的组件、服务以及指令等等封装成自定义模块,然后在根模块中加载。
1.新建模块【–routing 添加路由,可以不添加】
ng g module 文件夹名称/moduleName --routing
2.配置自定义模块
@NgModule({
//user模块中的组件
declarations: [ProfileComponent, AddressComponent, OrderComponent, UserComponent],
exports:[UserComponent], //模块向外暴露的组件,让其他模块可以使用当面模块中的组件
providers:[CommonService], //模块中的服务
imports: [ //模块中引用的模块
CommonModule
]
})
export class UserModule { }
3.在根模块中引入自定义模块
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
AppRoutingModule,
UserModule //引入我们的自定义模块
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
3.自定义模块及懒加载
1.新建模块【–routing 添加路由,可以不添加】
ng g module 文件夹名称/moduleName --routing
2.新建组件
ng g components ...
3.在模块的路由配置文件中进行配置
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [
{
path:'',
component:UserComponent,
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UserRoutingModule { }
3.在根模块的路由配置文件中进行配置
//配置路由的模块
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
//在此处配置路由
const routes: Routes = [
{
path:'user',
loadChildren:'./module/user/user.module#UserModule'
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }