视频来源
【建议1.5px倍速】Angular教程_Angular8 Angular9 Angular12入门实战视频教程-2023年更新【IT营】

Angular 初识

Angular 环境配置

npm install -g @angular/cli
cnpm install -g @angular/cli

备注:npm若安装慢,可尝试使用cnpm方式代替,需要先安装cnpm依赖

npm install -g cnpm --registry=https://registry.npm.taobao.org

Angular 创建项目

直接安装

ng new angularDemo

跳过依赖安装

ng new angularDemo --skip-install

项目创建完成后安装依赖并启动

npm install / cnpm install 
ng serve --open

Augular 开发工具推荐

工具:Vscode

工具插件:Angular Language Service

Angular 结构目录

  • *.spec.ts 属于测试文件,开发过程不需要关注

Angular 组件使用

命令行创建组件

使用命令创建组件,会自动引入并配置到app.module.ts

ng g component components/news

components/news 属于指定的目录/文件

补充

ng generate component dashboard --module=app.module

备注:需要指定--module=app.module,否则报错

Error: More than one module matches. Use skip-import option to skip importing the component into the closest module. More than one module matches. Use skip-import option to skip importing the component into the closest module.

组件使用方法

组件news.components.ts,其中selector为组件使用名称

import { Component } from '@angular/core';

@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.css']
})
export class NewsComponent {

}

app.component.html中使用方式

<!-- 新组件使用 -->
<app-news></app-news>

<!-- 原app.component.html内容-->
<div>
this is angular Index !
</div>

组件里面绑定数据

组件.ts定义一个属性title

规范定义属性格式

public student: string = "XXXX";
public test: any = 'XXXXX';
import { Component } from '@angular/core';

@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.css']
})
export class NewsComponent {

title = "我是一个新闻组件~";

}

news.component.html使用属性

<p>{{title}}</p>

页面预览显示

基本数据类型

参考博客

  • Boolean 布尔
  • number 数字
  • string 字符串
  • array 数组
  • any 任意类型
  • tuple 元组类型
  • enum 枚举
  • null和undefined
  • void类型
  • never类型

布尔

let flg : boolean = true;

数字

let a : number = 6;

字符串

Typescript支持使用单引号或双引号来表示字符串类型。支持使用模板字符串反引号(`)来定义多行文本和内嵌表达式。使用${expr}的形式嵌入变量或表达式。

let name : string = "Angular";
let year : number = 2;
let words : string = `你好${name}${year}`;

数组

let arr : number[] = [1,2];
let arr : Array<number> = [1,2];

元组

元组类型用来表示已知元素数量和类型的数组,各元素类型不必相同。

let xx : [string, number];
xx = ['Angular', 2];

枚举

enum Name {LI,WANG,ZHAO};
let nm : Name = Name.WANG;
alert(nm);//1
枚举默认下标是从0开始,可以手动修改。
enum Name2 {LI=3,WANG,ZHAO=8};
let nm2 : Name2 = Name2.WANG;
alert(nm2);//4
alert(Name2.ZHAO);//8

null和undefined

let x : number | null | undefined;

void类型

function hello() :void {alert("hello");}

never类型

never是其他类型的子类型,代表不会出现的值。声明为never类型的变量只能被never类型所赋值,在函数通常表现为抛出异常或无法执行到终止但(例如无限循环)

let x : never;
x = (() => {throw new Error('exeption occur')})();

在组件里面绑定属性

属性title的动态取值,需要用[]中括号包起来。

<div [title]="student">
this is angular Index !
</div>

在组件里面绑定html代码片段

htmlH:any = "<h1>我是html代码段!</h1>";
<span [innerHTML]="htmlH"></span>

引入图片

#静态文件资源目录`assets`下
<img src="assets/images/all.png" />

#图片资源目录由动态获取
<img [src]="pic"/>

Angular 组件方法/命令

在组件里面使用循环

arr = [12,234,231];

*ngFor="let item of arr 标准语法格式,arr为定义的数据对象

<ul>
<li *ngFor="let item of arr">
{{item}}
</li>
</ul>

循环数据显示数组的索引(key)

public list:any[] = [

{
"title":"我是标题01"
},
{
"title":"我是标题02"
},
{
"title":"我是标题03"
},

];
<ul>
<li *ngFor="let item of list;let key = index;">
{{key}} -- {{item.title}}
</li>
</ul>

ngif的使用

public flag:boolean = false;
<div *ngIf="flag">
{{flag}}
</div>
<div *ngIf="!flag">
{{flag}}
</div>

ngif搭配ngfor使用

方式01

[ngif]实现

<ul>
<li *ngFor="let item of list;let key = index;">

<span *ngIf="key == 2" class="red"> {{key}} -- {{item.title}} </span>
<span *ngIf="key != 2"> {{key}} -- {{item.title}} </span>

</li>
</ul>

方式02

[ngclass]实现

<ul>
<li *ngFor="let item of list;let key = index;">
<span [ngClass]="{'red': key==1,'blue':key==0}"> {{key}} -- {{item.title}} </span>
</li>
</ul>

ngswitch的使用

public orderStatus:number = 1; 
<span [ngSwitch]="orderStatus">
<p *ngSwitchCase="1">
订单已支付
</p>
<p *ngSwitchCase="2">
订单已支付并确认
</p>
<p *ngSwitchDefault>
订单未支付
</p>
</span>

ngclass的使用

<div>
<span [ngClass]="{'red': flag,'blue': !flag}"> ngclass属性 </span>
</div>

ngstyle的使用

静态方式写法

<p [ngStyle]="{'color':'red'}">我是一个p标签</p>

动态方式写法

主要arr,如果是动态取值,不加'单引号。静态方式写法需要加单引号。

public arr:string = 'red';
<p [ngStyle]="{'color':arr}">我是一个p标签</p>

管道

public today:any = new Date();
<P>{{today}}</P>
<p>{{today | date: 'yyyy-MM-dd HH:mm:ss'}}</p>

执行方法

<hr>

<button (click)="run()">run</button>

<hr>

<input type="text" (keydown)="keyDown($event)">
run(){
alert('执行自定义方法!');

}

keyDown(event: any){
if( event.code == 'Enter' ){
console.log('敲了一下回车');
}else{
console.log(event.code);
}
}

双向绑定 mvvm

需要在app.module.ts中引入FormsModule

import { FormsModule } from '@angular/forms';

并且在imports中声明当前FormModule的使用

@NgModule({
declarations: [
AppComponent,
NewsComponent,
HomeComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
public keywords:string = '';
<input type="text" [(ngModel)]="keywords">
{{keywords}}

Angular 服务引入

ng g service services/my_new_service

app.module.ts中声明服务

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

import {TestService} from './services/test.service';


@NgModule({
declarations: [
...
],
imports: [
...
],
providers: [TestService],
bootstrap: [...]
})
export class AppModule { }

在需要使用的component也需要在声明一次

import { TestService } from 'src/app/services/test.service';

官方推荐使用service的方式

通过构造方法注入参数对象

constructor(public test:TestService){
let t = this.test;
console.log(t.get());
}

Angular 操作原生dom节点

方式一

<div id="box">
this is a box !
</div>
<br>
<div id="box1" *ngIf="flag">
this is a box1 !
</div>
// 组件和指令初始化完成,不是dom加载完成
ngOnInit(): void {

let oBox:any = document.getElementById('box');
console.log(oBox.innerHTML);
oBox.style.color = 'red';

// let oBox1:any = document.getElementById('box1');
// console.log(oBox1.innerHTML);
// oBox1.style.color = 'red';
}

//视图加载完成后触发的方法,dom加载完成 (建议把dom操作放这里)
ngAfterViewInit(): void {

let oBox1:any = document.getElementById('box1');
console.log(oBox1.innerHTML);
oBox1.style.color = 'red';
}

方式二

引入

import { ViewChild } from '@angular/core';

声明

<div #box2>
我是一个dom节点
</div>

赋值

//获取dom节点并赋值box2
@ViewChild('box2') box2:any;

使用

ngAfterViewInit(): void {
console.log(this.box2.nativeElement);

this.box2.nativeElement.style.width= 200;
this.box2.nativeElement.style.height= 200;
this.box2.nativeElement.style.background= 'red';
}

Angular 组件间的传值

父->子组件间的传值

1.这里示例是父组件->子组件传值

2,若需要父组件使用子组件,则@ViewChild是一种方法

传值

父组件定义传值参数

public title:string = '父组件传值';

父组件页面html引入子组件

title 是父组件传值参数

<app-son [title]="title"></app-son>

子组件引入Input模块

import { Input } from '@angular/core';

子组件接收值

@Input() title:any;

传方法

父组件定义方法

run(){
alert('父组件的方法!');
}

父组件页面html引入子组件

‘run’不需要加(),表示的是方法,而不是执行方法

<app-son [run]='run'></app-son>

子组件调用

@Input() run:any;

runParentsMethod(){
this.run();
}

传递组件

父组件页面html引入子组件

‘this’表示的是整个组件

<app-son [home]='this'></app-son>

子组件调用

@Input() home:any;

runParentsMethod(){
<!-- this.run(); -->

//获取父组件的值
alert(this.home.msg);

//调用父组件方法
this.home.run();
}

子组件通过@output触发父组件方法

比较复杂,用的比较少,但是要知道。

子组件引入output和EventEmitter

import { Output,EventEmitter } from '@angular/core';

子组件中实例化EventEmitter

@Output() private outer = new EventEmitter<string>();

子组件通过EventEmitter对象outer实例广播数据

sendParent(){
this.outer.emit('msg from child');
}

父组件调用子组件时候,定义接收事件,outer就是子组件EventEmitter对象outer

<app-header (outer)="runParent($event)">
</app-header>

父组件接收到数据会调用自己的runParent方法,这个时候就可以拿到子组件数据

runParent(e){
//e 就是子组件传值给父组件的参数
console.log(e);
}

拓展:非父子组件通信

  • localstage
  • 服务形式(service公有的组件)

Angular 异步数据编程

TestService服务调用异步方法

//同步方法
get(){
return 'this is a test service !';
}

//异步方法
//1.回调函数处理异步方法数据
getCallBackData(cb:any){

setTimeout(() => {
var name = '张三';
cb(name);
}, 1000);

}

//2. promise处理异步方法数据
getPromiseData(){

return new Promise((resolve,reject)=>{

//resolve(); 成功执行函数
//reject(); 失败执行函数

setTimeout(() => {
var name = '张三--promise';
resolve(name);
}, 1000);
});


}

//3. rxjs 处理异步方法数据
getrxjsData(){

return new Observable(observe=>{

//成功数据返回
// observe.next();
//失败数据返回
// observe.error();

setTimeout(() => {
var name = '张三--rxjs';
observe.next(name);
}, 1000);

});

}

获取异步方法返回参数结果

ngOnInit(): void {

//同步方法
this.msg = this.testService.get();
console.log(this.msg);

//异步方法
this.testService.getCallBackData((data:any)=>{
console.log(data);
});

//Promise
var promiseData = this.testService.getPromiseData();
promiseData.then((data)=>{
console.log(data);
});

//rxjs
var rxjsData = this.testService.getrxjsData();
rxjsData.subscribe((data)=>{
console.log(data);
});

}

rxjs取消订阅

var rxjsData = this.testService.getrxjsData();
let d = rxjsData.subscribe((data)=>{
console.log(data);
});
setTimeout(() => {
d.unsubscribe(); //取消订阅
}, 1000);

rxjs多次执行异步方法

Promise方法不能多次执行(没有这个能力)

//4. rxjs 多次执行处理异步方法数据
getrxjsIntervalData(){

return new Observable(observe=>{

//成功数据返回
// observe.next
//失败数据返回
// observe.error

let count = 0 ;

setInterval(() => {
count ++ ;

var name = '张三--rxjs-interval-'+count;
observe.next(name);
}, 3000);

});

}

rxjs的工具函数map\filter

import {map,filter} from 'rxjs/operators';
let number = this.testService.getRxjxIntervalNumData();
number.pipe(

//过滤工具
filter((value:any)=>{
if(value%2==0){
return true;
}else{
return false;
}
})

//多个工具组合使用,用','号隔开
,

//map工具
map((value:any)=>{
return value * value ;
})

).subscribe((data)=>{
console.log(data);
});

Angular 数据交互

国外测试接口网站

get请求数据

app.module.ts中引入HttpClientModule并注入

import {HttpClientModule} from '@angular/common/http'
@NgModule({
declarations: [
...
],
imports: [
HttpClientModule
],
providers: [...],
bootstrap: [...]
})
export class AppModule { }

在需要使用组件中,引入并在构造方法中声明对象

import {HttpClient} from '@angular/common/http';
constructor( public http: HttpClient ){
}

get方法调用

get(){
console.log('get方法调用~');
let api = "https://reqres.in/api/users?page=2";
this.http.get(api).subscribe((response)=>{
console.log(response);
});
}

post 提交数据

在需要使用组件中,引入并在构造方法中声明对象

post需要设置请求头,需要HttpHeaders模块

import {HttpClient,HttpHeaders} from '@angular/common/http';

post(){
console.log('post方法调用~');

const httpOptions = {
headers: new HttpHeaders({'Content-Type':'application/json'})
};

let api = "https://reqres.in/api/users";
this.http.post(api,'{"name": "morpheus","job": "leader"}',httpOptions).subscribe((response:any)=>{
console.log(response);
});

}

JsonP

跨域的一种解决方案

import {HttpClientModule,HttpClientJsonpModule} from '@angular/common/http';
@NgModule({
declarations: [
...
],
imports: [
HttpClientModule,
HttpClientJsonpModule
],
providers: [...],
bootstrap: [...]
})
export class AppModule { }

JsonP需要服务器后端支持

验证是否支持方法:

url?callback=xxx

url?cb=xxx

可响应接口参数返回是否有xxx标识名称(xxx是自己定义的一个参数,非必须按xxx标识参数使用)

jsonP(){
console.log('jsonP~');
//jsonP请求,服务器必须支持jsonP

this.http.jsonp('url','callback').subscribe((response)=>{
console.log(response);
});

}

使用第三方工具axios请求

axios

安装模块

npm install axios --save

引入模块

import axios from 'axios';

封装service服务供组件调用

import { Injectable } from '@angular/core';
import axios from 'axios';

@Injectable({
providedIn: 'root'
})
export class HttpServiceService {

constructor() { }

axiosGet(api:string){

return new Promise((reslove,rject)=>{

axios.get(api)
.then(function (response) {

// console.log(response);

reslove(response);
})

})


}

}

组件中使用

import { Component } from '@angular/core';
import {HttpClient,HttpHeaders} from '@angular/common/http';
import { HttpServiceService } from 'src/app/services/http-service.service';

@Component({
selector: 'app-demo04',
templateUrl: './demo04.component.html',
styleUrls: ['./demo04.component.css']
})
export class Demo04Component {

constructor( public http: HttpClient ,public httpservice: HttpServiceService ){

}

axios(){
console.log('axios方法调用~');
let api = "https://reqres.in/api/users?page=2";
this.httpservice.axiosGet(api).then((data)=>{
console.log(data);
});
}

}

Angular 路由

创建新项目时候,需要确认路由创建。

路由文件名app-routing.module.ts

创建的组件需要挂载到路由中

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'},

导航选中激活

active对应样式名

<a routerLink='/product' routerLinkActive="active" >product</a>

get 传值

<a [routerLink]="[ '/newscontent' ]" [queryParams]="{'aid':key}">{{item}}</a>

子组件接收传参

import { ActivatedRoute } from '@angular/router';
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
selector: 'app-newscontent',
templateUrl: './newscontent.component.html',
styleUrls: ['./newscontent.component.css']
})
export class NewscontentComponent {

constructor(public route:ActivatedRoute){
}

ngOnInit(): void {
this.route.queryParams.subscribe((data)=>{
console.log(data);
});
}

}

动态路由传值

:aid是动态路由传值需要获取的参数名称

{path:'newscontent/:aid',component:NewscontentComponent},

传值

<ul><li *ngFor="let item of list;let key = index">


<!-- get传值 -->
<!-- <a [routerLink]="[ '/newscontent' ]" [queryParams]="{'aid':key}">{{item}}</a> -->
<!-- 动态路由传值 -->
<a [routerLink]="[ '/newscontent/',key ]" >{{item}}</a>

</li></ul>

接收

ngOnInit(): void {

this.route.params.subscribe((data:any)=>{
console.log(data);
});

}

动态路由的js跳转

import { Router } from '@angular/router';

js跳转

goJs(){
console.log('js路由跳转~');
this.router.navigate(['/newscontent/','123']);
}

get传值跳转路由

【Angular教程_Angular8 Angular9 Angular12入门实战视频教程-2023年更新【IT营】】- P14 - 21:36进度处

父子嵌套路由

父子嵌套路由修改

const routes: Routes = [
{path:'home',component:HomeComponent,children:[
{path:'menu01',component:Menu01Component},
{path:'menu02',component:Menu02Component},
]}
];

父页面添加路由组件

<div>

<div class="left">
<a [routerLink]="[ '/home/menu01' ]">菜单01</a>
<a [routerLink]="[ '/home/menu02' ]">菜单02</a>
</div>

<div class="right">
<router-outlet></router-outlet>
</div>

</div>

Ionic

Angular + Ionic 可以开发app

目前暂无学习规划,待Angular知识吸收归纳后跟进。