Angular
此笔记根据b站IT营视频学习所做的笔记,使用的是 angular 11.2.3,视频链接如下 b站学习视频
1.环境配置
shell
# 更换镜像源
npm config set registry https://registry.npmmirror.com
# 查看是否成功
npm config get registry
# 切换node源
nvm use 12.22.12
# 验证node版本
node -v
npm -v
# 安装脚手架
npm install -g @angular/cli
npm install -g @angular/cli@11.2.3
# 查看ng版本
ng version
2.创建项目
shell
ng new angulardemo01
ng new angulardemo01 --skip-install
cd angulardemo01
npm install
ng serve --open
2.1 app.module
js
/* 这个文件是Angular根模块,告诉Angular如何组装应用 */
// 浏览器解析模块
import { BrowserModule } from '@angular/platform-browser';
// Angular 核心模块
import { NgModule } from '@angular/core';
// 根组件
import { AppComponent } from './app.component';
/* NgModule装饰器,接受一个元数据对象,告诉 Angular 如何编译和启动应用 */
@NgModule({
declarations: [ /** 配置当前项目运行的组件 */
AppComponent
],
imports: [ /** 配置当前模块运行依赖的其它模块 */
BrowserModule
],
providers: [], /** 配置项目所需要的服务 */
bootstrap: [AppComponent] /** 指应用的主视图(称为根组件)通过引导根AppModule来启动应用 */
})
// 暴露出去的模块,此处为根模块,不需要给其他人暴露
export class AppModule { }
2.2 app.component.ts
js
// 引入核心模块的 Component
import { Component } from '@angular/core';
@Component({
selector: 'app-root', // 使用这个组件的名称
templateUrl: './app.component.html', // html
styleUrls: ['./app.component.scss'] //css
})
export class AppComponent {
title = 'angulardemo01'; // 定义属性
constructor(){ //构造函数
}
}
2.3 新建组件
js
ng g component components/new
组件new
ng g component components/home
3. 属性
js
public title = '新闻title';
msg = '我是一个新闻组件的msg';
username:String = '用户名';
public student:any = 123;
public userinfo:any={
username:'张三',
age:'20'
}
// 推荐
public studentText:any = '我是一个学生的简介属性';
// 推荐
public list:any=['第一个新闻',22222,'我是第三个新闻']
public message:any;
public items:Array<number> = [123,234,546]
public cars:any = [
{
cate:'宝马',
list:[{
title:'宝马x1',
price:'10万'
},
{
title:'宝马x2',
price:'20万'
},
{
title:'宝马x3',
price:'30万'
}]
},
{
cate:'奥迪',
list:[{
title:'奥迪q1',
price:'40万'
},
{
title:'奥迪q2',
price:'50万'
},
{
title:'奥迪q3',
price:'60万'
}]
}
]
constructor() {
this.message = '这是给属性赋值--改变属性的值'
console.log(this.message);
this.msg = '我是改变属性后的值 '
}
4. 数据绑定
js
<div [title]="student">
张三
</div>
<span [innerHtml] = 'content' class="red"></span>
<ul>
<li *ngFor="let item of items">
{{item}}
</li>
</ul>
<ul>
<li *ngFor="let item of userlist">
{{item.username}} --- {{item.age}}
</li>
</ul>
<ul>
<li *ngFor="let item of cars">
<h2>{{item.cate}}</h2>
<ol>
<li *ngFor="let car of item.list">
{{car.title}} --- {{car.price}}
</li>
</ol>
</li>
</ul>
5.条件判断语句
ngStyle ngClass
js
<ul>
<li *ngFor="let item of list;let key=index;">
<span *ngIf="key == 1" class="red"> {{key}} --- {{item.title}} </span>
<span *ngIf="key != 1"> {{key}} --- {{item.title}} </span>
</li>
</ul>
<h1>条件判断语句 ngif</h1>
<div *ngIf="!flag">
<img src="assets/images/pic1.png" alt="随便写的" />
</div>
<div *ngIf="flag">
<img [src]="picURL" />
</div>
<div [ngSwitch]="orderStatus">
<div *ngSwitchCase="1">已支付</div>
<div *ngSwitchCase="2">支付并确认</div>
<div *ngSwitchCase="3">已发货</div>
<div *ngSwitchCase="4">已收获</div>
<div *ngSwitchCase="5">无效订单</div>
<div *ngSwitchDefault>output2</div>
</div>
<ul>
<li *ngFor="let item of list;let key = index;">
<span *ngIf="key==1" [ngClass]="{'red': key==1}">{{key}} ---- {{item.title}}</span>
<span *ngIf="key==2" [ngClass]="{'orange': key==2}">{{key}} ---- {{item.title}}</span>
</li>
</ul>
<p style="color: red">我是一个p标签</p>
<p [ngStyle]="{color: 'red'}">我是一个p标签</p>
<p [ngStyle]="{color: attr}">我是一个p标签</p>
6.管道
js
<h2>管道</h2>
{{today | date:'yyyy-MM-dd HH:mm:ss'}}
<button (click)="run()">执行事件</button>
<hr/>
<button (click)="getData()">执行方法获取数据</button>
<hr/>
<span>{{title}}</span>
<button (click)="setData()">执行方法设置数据</button>
<h1>表单事件 事件对象</h1>
keydown:<input type="text" (keydown)="keydown($event)">
keyup:<input type="text" (keyup)="keyUp($event)">
runEvent
<button (click)="runEvent($event)">执行方法获取事件对象</button>
7.表单对象、事件对象
js
app.moudle.ts
import { FormsModule } from '@angular/forms'
imports: [
FormsModule
],
<input type="text" [(ngModel)]="keywords">
{{keywords}}
<button (click) = "changeKeywords()" >改变keywords</button>
<button (click) = "getKeywords()" >获取keywords</button>
8.数据持久化
js
ng g service services/storage
# app.module.ts
import { StorageService } from './services/storage.service'
providers: [StorageService],
# 其它组件引用不推荐()
import { StorageService } from '../../services/storage.service';
// 不推荐
var storage = new StorageService();
# 推荐
import { StorageService } from '../../services/storage.service';
constructor(public storeage:StorageService) {
this.storeage.get();
}
set(key:string,value:any){
localStorage.setItem(key,JSON.stringify(value))
}
get(key:string){
var item:any = localStorage.getItem(key)
if(item){
return JSON.parse(item);
}
return null;
}
remove(key:string){
localStorage.removeItem(key);
}
9.原生操作dom
js
// 视图加载完成后执行的方法,建议把dom操作放在这里
ngAfterViewInit():void{
let box1:any= document.getElementById('box1');
// console.log(box2.innerHTML)
box1.style.color = 'blue'
}
10.viewchild-父组件调用子父组件属性
js
# html
<div #mybox>
我是一个div
</div>
@ViewChild('mybox') mybox:any;
constructor() { }
# typescript
ngAfterViewInit(){
console.log(this.mybox.nativeElement.innerHTML)
this.mybox.nativeElement.style.width = '100px';
this.mybox.nativeElement.style.height = '100px';
this.mybox.nativeElement.style.background = 'red'
}
11.viewchild 父组件调用子组件的方法
js
# html
<app-header #header></app-header>
<p>news works!</p>
<div #mybox>
我是一个div
</div>
<button (click) = 'clickMethod()'>点击</button>
# typescript
@ViewChild('mybox') mybox:any;
@ViewChild('header') header:any
constructor() { }
clickMethod(){
this.header.run();
}
12. css3 动画
js
# html
<div class="content">
内容区域
<button (click)="showAside()">显示侧边栏</button>
<button (click)="hiddenAside()">隐藏侧边栏</button>
</div>
<aside id='aside'>
这是一个侧边栏
</aside>
# css
#aside{
width: 200px;
height: 100%;
position: absolute;
right: 0px;
top: 0px;
background: #000;
color: #fff;
transform: translate(100%,0);
transition: all 2s;
}
# typescript
showAside(){
var asideDom:any = document.getElementById('aside');
asideDom.style.transform = "translate(0,0)";
}
hiddenAside(){
var asideDom:any = document.getElementById('aside');
asideDom.style.transform = "translate(100%,0)";
}
13.父子组件的通信-属性
js
# 父1 typescripe
public title:string = '我是一个首页标题-news'
# 父1 html
<app-header #header [title]="title"></app-header>
# 父2 typescripe
public title:string = '我是一个首页标题-home'
# 父2 html
<app-header #header [title]="title"></app-header>
# 子组件
<h1 style="background: red;">{{title}}</h1>
@Input() title:any;
14.父子组件的通信-方法
js
# 父1 typescripe
run(){
alert('我是news的run方法')
}
# 父1 html
<app-header [title]="title" [run]="run"></app-header>
# 父2 typescripe
run(){
alert('我是home的run方法')
}
# 父2 html
<app-header [title]="title" [run]="run"></app-header>
# 子 typescript
@Input() run:any;
gerParentRun(){
this.run();
}
# 子 html
<button (click) = "gerParentRun()">子组件执行父组件的run()</button>
# 传递父组件
<app-header [home]="this"></app-header>
15.@Output 子组件给父组件广播,调用父组件方法
js
# 父组件 html
<app-footer (outer)="runOuter($event)"></app-footer>
# 父组件 ts
runOuter(e:any){
alert('我是home组件的runOuter方法')
console.log(e)
}
# 子组件 html
<button (click)="sendParent()">通过@Output给父组件广播</button>
# 子组件 ts
sendParent(){
this.outer.emit("我是子组件的数据")
}
16.生命周期函数(勾子方法)
| 阶段 | 方法 | 摘要 |
|---|---|---|
| 创建 | constructor |
标准 JavaScript 类构造函数。当 Angular 实例化组件时运行。 |
| 变更检测 | ngOnInit |
在 Angular 初始化完组件的所有输入之后运行一次。 |
ngOnChanges |
每次组件的输入发生更改时都会运行。 | |
ngDoCheck |
每次检查此组件是否有更改时都会运行。 | |
ngAfterContentInit |
在组件的内容初始化之后运行一次。 | |
ngAfterContentChecked |
每次检查此组件内容是否有更改时都会运行。 | |
ngAfterViewInit |
在组件的视图初始化之后运行一次。 | |
ngAfterViewChecked |
每次检查组件的视图是否有更改时都会运行。 | |
| 渲染 | afterNextRender |
在所有组件下次渲染到 DOM 后运行一次。 |
afterEveryRender |
每次所有组件渲染到 DOM 后都会运行。 | |
| 销毁 | ngOnDestroy |
在组件销毁之前运行一次。 |
实例
js
constructor() {
console.log('constructor')
}
ngOnInit(): void {
console.log('ngOnInit')
}
ngOnChanges(): void {
console.log('ngOnChanges 父子组件传值触发')
}
ngDoCheck(){
console.log('03ngDoCheck --- 检测,并在发生angular 无法或者不愿意自己检测的变化时作出的反应')
}
ngAfterContentInit(){
console.log('04ngAfterContentInit ---- 当把内容投影进组件之后调用')
}
ngAfterContentChecked(){
console.log('05ngAfterContentChecked --- 每次完成被投影组件内容的变更检测之后调用')
}
ngAfterViewInit(){
console.log('06ngAfterViewInit --- 初始化组件视图及子视图之后调用(dom操作在这里面)')
}
ngAfterViewChecked(){
console.log('07ngAfterViewChecked --- 每次做完组件视图和子视图的变更检测之后调用')
}
afterNextRender(){
console.log('afterNextRender')
}
afterEveryRender(){
console.log('afterEveryRender')
}
ngOnDestroy(){
console.log('08ngOnDestroy')
}
17.常见的异步编程的几种方法。
17.1.回调函数
js
// 异步回调定义
getCallbackData(cb:any){
setTimeout(() => {
var username = '张三';
cb(username)
}, 1000);
}
// 使用异步回调
ngOnInit(): void {
let data = this.request.getCallbackData((data:any) =>{
console.log(data)
});
console.log(data)
}
17.2.promise
js
// 定义promise
getPromiseData(){
return new Promise((resolve,reject)=>{
setTimeout(() => {
var username = '张三';
resolve(username)
}, 1000);
})
// 使用promise
var promiseData = this.request.getPromiseData();
promiseData.then((data)=>{
console.log('promiseData-',data)
})
17.3 rxjs
js
// rxjs定义
getrxjsData(){
return new Observable((observer)=>{
setTimeout(() => {
var username = '李四';
observer.next(username);
// observer.error('失败')
}, 2000);
})
}
// rxjs 获取异步数据
var observerData = this.request.getrxjsData();
observerData.subscribe((data)=>{
console.log('rxjs-observerdata',data)
})
17.4 rxjs 撤回
js
// 过一秒后撤回rxjs的操作
var streem = this.request.getrxjsData();
var d = streem.subscribe((data)=>{
console.log('rxjs-observerdata',data)
})
setTimeout(() => {
d.unsubscribe(); // 取消订阅
}, 1000);
17.5 rxjs 多次执行
js
// rxjs 多次执行
getrxjsIntervalData(){
return new Observable((observer) => {
var count = 0;
setInterval(()=>{
count ++;
var username = '王五' + count
observer.next(username)
}, 1000)
})
}
// 多次执行
var rxjsInterval = this.request.getrxjsIntervalData();
rxjsInterval.subscribe(data =>{
console.log(data)
})
17.6 map,filter
js
import {map,filter} from 'rxjs/operators'
用工具方法对返回的数据做处理
// 方法定义
getRxjsIntervalNum(){
return new Observable(observer=>{
var count = 0;
setInterval(()=>{
count++;
observer.next(count)
},2000)
})
}
// 管道
var rxjsNum = this.request.getRxjsIntervalNum();
rxjsNum.pipe(
filter((value:any) :any =>{
if(value % 2 == 0){
return true;
}
})
).subscribe(data =>{
console.log(data)
})
// map
var rxjsNum = this.request.getRxjsIntervalNum();
rxjsNum.pipe(
map((value:any) :any =>{
return value*value;
})
).subscribe(data =>{
console.log(data)
})
// filter + map
var rxjsNum = this.request.getRxjsIntervalNum();
rxjsNum.pipe(
filter((value:any) :any =>{
if(value % 2 == 0){
return true;
}
}),
map((data:any):any =>{
return data*data;
})
).subscribe(data =>{
console.log(data)
})
console.log('ngOnInit')
}
18. angular 中的数据交互(get jsonp post)
18.1 get
js
# app.moudle
import {HttpClientModule} from '@angular/common/http'
# 具体的模块
import {HttpClient} from '@angular/common/http'
executeGet(){
let api = 'http://a.itying.com/api/productlist';
this.http.get(api).subscribe((data:any) =>{
console.log(data)
})
}
18.2 post
js
# app.moudle
import {HttpClientModule} from '@angular/common/http'
# 具体的模块
import {HttpClient,HttpHeaders} from '@angular/common/http'
// 存在跨域问题
doLogin(){
const httpOptions = {headers: new HttpHeaders({'Content-Type':'application/json'})}
let jsonObj = {
'username': '张三',
'age':20
}
let api = 'http://127.0.0.1:3000/dologin'
this.http.post(api,jsonObj,httpOptions).subscribe((response)=>{
console.log(response)
})
}
18.3 jsonp
js
# app.moudle
import {HttpClientModule,HttpClientJsonpModule} from '@angular/common/http'
# 具体的模块
import {HttpClient,HttpHeaders} from '@angular/common/http'
constructor(public http:HttpClient) { }
// 支持跨域
getJsonpData(){
let api = 'http://a.itying.com/api/productlist';
/**
* 验证是否支持jsonp格式 http://a.itying.com/api/productlist?callback=aaaa
* http://a.itying.com/api/productlist?cb=aaaa
* */
this.http.jsonp(api,'callback').subscribe(response =>{
console.log(response)
})
}
18.4 axios
js
npm install axios --save
# app.moudle
import { HttpserviceService } from 'src/app/services/httpservice.service';
providers: [StorageService,RequestService,HttpserviceService],
# 具体的模块
import { HttpserviceService } from '../../services/httpservice.service'
constructor(
public http:HttpClient,
public httpservice:HttpserviceService
) { }
19 路由跳转
19.1 普通路由跳转
js
# app.route.moule.ts
import { NewsComponent } from './components/news/news.component';
import { HeadersComponent } from './components/headers/headers.component';
import { HomeComponent } from './components/home/home.component';
import { TaskComponent } from './components/task/task.component';
const routes: Routes = [
{
path:'home', component:HomeComponent
},{
path:'task', component:TaskComponent
},{
path:'news',component:NewsComponent
},{
path:'header',component:HeadersComponent
},// 匹配不到路由情况西按默认跳转到home,记住要放在最后
{
path:'**',
redirectTo:'home'
},
];
# app.html
<h1>我是根组件</h1>
<header class="header">
<a [routerLink]="['/task']" routerLinkActive="router-link-active" ]>任务</a>
<a [routerLink]="['/header']" routerLinkActive="router-link-active" >头部</a>
<a [routerLink]="['/home']" routerLinkActive="router-link-active" >主页</a>
<a [routerLink]="['/news']" routerLinkActive="router-link-active" >新闻页</a>
</header>
<router-outlet></router-outlet>
19.2 路由链接传参数
js
// 新闻页
<ul>
<li>
<a [routerLink]="['/content']" [queryParams]="{aid:1}" >链接1</a>
</li>
<li>
<a [routerLink]="['/content']" [queryParams]="{aid:2}" >链接2</a>
</li>
</ul>
// 新闻详情页
import { ActivatedRoute } from '@angular/router'
constructor(
public route : ActivatedRoute
) { }
ngOnInit(): void {
console.log(this.route.queryParams)
this.route.queryParams.subscribe((data:any)=>{
console.log(data)
})
}
19.3 动态路由
js
# app.route.moudle.ts
{
path:'detail/:aid',component:DetailComponent
}
# html
<ul>
<li>
<a [routerLink]="['/detail' , 1]" >详情1</a>
</li>
<li>
<a [routerLink]="['/detail' , 2]" >详情2</a>
</li>
</ul>
# detail.ts
import { ActivatedRoute } from '@angular/router'
constructor(
public route:ActivatedRoute
) { }
ngOnInit(): void {
this.route.params.subscribe((data:any) =>{
console.log(data)
})
}
19.4 动态路由的js跳转
js
# ts
import { Router } from '@angular/router';
constructor(public router:Router) { }
goProductContent(){
// 路由跳转 普通路由
this.router.navigate(['/productcontent']);
}
goDetail(){
// 动态路由
this.router.navigate(['/detail',9]);
}
# html
<button (click)="goProductContent()">前往产品详情页</button>
19.5 路由get传值js跳转
js
goContent(){
let queryParams:NavigationExtras = {
queryParams:{
'aid':99
}
}
this.router.navigate(['/content'],queryParams);
}
20 父子路由、嵌套路由、默认跳转子路由
js
# route.moudle.ts
{
path:'home', component:HomeComponent,
children:[
{
path:'sysconfig',component:SysmanageComponent
},{
path:'taskmange',component:TaskmanageComponent
},{
path:'**',
redirectTo:'sysconfig'
}]
},{
path:'task', component:TaskComponent,
children:[
{
path:'systask',component:SystaskComponent
},{
path:'cvstask',component:CvstaskComponent
},{
path:'**',
redirectTo:'systask'
}
]
}
# html
<div class="content">
<div class="left">
<a [routerLink]="['/home/sysconfig']" routerLinkActive="router-link-active" >系统配置</a>
<br>
<a [routerLink]="['/home/taskmange']" routerLinkActive="router-link-active" >任务管理</a>
<br>
</div>
<div class="right">
<router-outlet></router-outlet>
</div>
</div>
# html-2
<div class="content">
<div class="left">
<a [routerLink]="['/task/systask']" routerLinkActive="router-link-active" >主机漏扫任务</a>
<br>
<a [routerLink]="['/task/cvstask']" routerLinkActive="router-link-active" >网站检测任务</a>
<br>
</div>
<div class="right">
<router-outlet></router-outlet>
</div>
</div>