Angular 学习笔记

Angular 学习笔记

一 Angular 环境搭建

1. 安装前准备工作

安装 node.js
安装 cnpm

2. 全局安装 Angular 脚手架

cnpm install -g @angular/cli

3. 测试安装是否成功

命令控制台中输入: ng v

如果出现以下画面,则安装成功

在这里插入图片描述

二 Angular 创建项目

1. 在要创建项目的文件夹中打开 cmd 命令控制台
2. 创建项目

ng new 项目名称  (直接安装,安装的过程中自动执行 npm i,该命令安装依赖较慢,很有可能安装失败)
ng new 项目名称 --skip-install  (建议, 跳过 npm i 安装,不会安装项目所需要的依赖)

安装过程中会选择是否安装路由,选择css预处理器等

3. 安装项目依赖

cnpm i  (在项目根目录中执行)

4. 运行项目

ng serve --open  (在项目根目录中执行)

三 Angular 根模块文件分析

根组件:

src/app/app.component.html
src/app/app.component.scss
src/app/app.component.ts

根模块文件 app.module.ts:
根模块文件 app.component.ts

四 Angular 常用命令行

新建项目:
		ng new 项目名称  (直接安装,安装的过程中自动执行 npm i,该命令安装依赖较慢,很有可能安装失败)
		ng new 项目名称 --skip-install  (建议, 跳过 npm i 安装,不会安装项目所需要的依赖)
		
运行项目: ng serve --open

创建一个组件: ng g component (文件路径/)组件名  注:执行该指令会自动在 app.module.ts 中引入并注册组件

创建一个服务: ng g service (文件路径/)服务名称

五 数据、属性绑定,指令

1. 数据绑定

			我们使用 {{ title }} 的形式将 ts 中的属性绑定到页面视图中

2. 属性绑定

			<div [title]="student"></div>,我们使用 [] 将 ts 中的属性绑定到页面标签的属性中,页面标签的属性就可以动态改变了

3. html 绑定

			<span [innerHTML]="content"></span>
			ts中: public content:string = "<h2>我是一个h2标签</h2>"

4. 动态class

			<span [ngClass]="{'red': flage, 'blue': true}"></span>	
			ts 中: public flage = false;

5. 动态style

			<p [ngStyle]="{‘color’: 'red', 'width': pWidth}"></p>
			ts中: public pWidth:string = '50px'

6. 数据循环: *ngFor

			<div *ngFor="let item of list; let key=index;">{{ item }}</div> 
			ts中: public list:any[] = ['111', 222 , '333']

7. 条件判断: *ngIf

8. 条件判断语句 [ngSwitch] 和 *ngSwitchCase

			<span [ngSwitch]="option">
			    <p *ngSwitchCase="1">
			        {{1}}
			    </p>
			    <p *ngSwitchCase="2">
			        {{2}}
			    </p>
			    <p *ngSwitchDefault>
			        {{3}}
			    </p>
			</span>
			ts 中: public option:number = 2;

六 属性修饰符(声明属性的几种方式)

public				共有类型(默认)				可以在这个类里面使用,也可以在类外面使用
protected			保护类型						只有在当前类和它的子类中使用
private				私有类型						只有在当前类才可以访问这个属性

七 管道

Angular 中的管道其实就是过滤器,用来转换数据然后显示给用户

内置管道

管道详情
DatePipe根据区域设置规则格式化日期值
UpperCasePipe把文本转换成全大写形式
LowerCasePipe把文本转换成全小写形式
CurrencyPipe把数字转换成货币字符串,根据语言环境中的规则进行格式化
DecimalPipe把数字转换成带小数点的字符串,根据语言环境中的规则进行格式化
PercentPipe把数字转换成百分比字符串,根据语言环境中的规则进行格式化
AsyncPipe从一个异步回执中解出一个值
I18nPluralPipe将值映射到根据语言环境规则对该值进行复数化的字符串
I18nSelectPipe通用选择器,用于显示与当前值匹配的字符串
JsonPipe把一个值转换成 JSON 字符串格式。在调试时很有用
KeyValuePipe将 Object 或 Map 转换为键值对数组
SlicePipe从一个 Array 或 String 中创建其元素一个新子集(slice)
TitleCasePipe把文本转换成标题形式。 把每个单词的第一个字母转成大写形式,并把单词的其余部分转成小写形式。 单词之间用任意空白字符进行分隔,比如空格、Tab 或换行符

具体用法详见 Angular 官方文档—管道

八 事件绑定

我们使用()将事件绑定到 ts 中

绑定点击事件

<button (click)="clickFun()">点击按钮触发方法</button>

绑定表单事件

绑定键盘按下抬起事件:
		<input (keydown)="onKeyDown()"></input>
		<input (keyup)="onKeyUp()"></input>

将事件对象传入方法中:

		<button (click)="clickFun($event)">点击按钮触发方法</button>
		<input (keydown)="onKeyDown($event)"></input>
		<input (keyup)="onKeyUp($event)"></input>	
		ts 中: onKeyDown(e){
					console.log(e)
				}

九 双向数据绑定

MVVM 模式,只是针对表单

首先得在 app.module.ts 中引入 FormsModule 模块, 并注册

在这里插入图片描述

我们使用 [()] 的方式对表单元素进行双向绑定

<input type="text" [(ngModel)]="title" (keydown)="onKeyDown($event)">

public title:string = "vvv"
onKeyDown(e:any){
    if(e.keyCode === 13){ // 13 是回车按键
      console.log(this.title)
    }
}

十 Angular 服务

服务(service),所有组件都可以使用,通常我们把公共的方法放在服务里面,这样多有组件都能够共享这些方法

创建服务

ng g service (指定路径/)服务名称

编写服务代码

在这里插入图片描述

在 app.module.ts 中引用并配置服务

在这里插入图片描述

组件中使用服务

在这里插入图片描述

十一 数据持久化

我们可以在服务中使用 localStorage 和 sessionStorage 来实现我们的数据持久化

// storage.service.ts
// localStorage 实例

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

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

  constructor() { }

  save(key:string, val:any){
    localStorage.setItem(key, JSON.stringify(val))
  }

  get(key:string){
    let v = localStorage.getItem(key)
    return v ? JSON.parse(v) : null
  }

  delete(key:string){
    localStorage.removeItem(key)
  }
}

十二 Angular 中的 ViewChild

原生 JS DOM操作:

let node:any = document.getElementById('box')
...
....
.....

Angular 提供的 DOM 操作(ViewChild):

1. 在模板中用 # 给 dom 起一个名字
		<div #myBox>我是一个节点</div>
		
2. 在业务逻辑里面引入 ViewChild
		import { Component, OnInit, ViewChild } from '@angular/core';
		
3. 通过 ViewChild 装饰器获取节点(写在类里面,构造函数上面)
		@ViewChild('myBox') myBox:any

4. 在 ngAfterViewInit 生命周期函数中处理 dom
 		let node:any = this.myBox.nativeElement
 		node.style.color = 'red'

父组件中通过 ViewChild 获取子组件的属性以及调用子组件的方法

1. 用 # 给子组件取个名字
		<app-header #header></app-header>

2. 在业务逻辑里面引入 ViewChild
		import { Component, OnInit, ViewChild } from '@angular/core';
		
3. 通过 ViewChild 装饰器获取子组件(写在类里面,构造函数上面)
		@ViewChild('header') header:any

4. 获取子组件的属性,调用子组件中的方法
		console.loga(this.header.title)
		this.header.run()

十三 组件通讯

1. 父组件传值(属性以及方法)给子组件

父组件定义一个属性 title,方法 run
		public title:string = '我是父组件的 title'
		run(){ console.log(111) }

在子组件中绑定父组件的属性
		<app-header [title]="title" [run]="run"></app-header>

子组件中引入 Input 装饰器
	 	import { Component, OnInit, Input} from '@angular/core'

子组件业务 ts 的类中通过 Input 装饰器获取父组件传过来的属性(写在构造函数的前面)
		 @Input() title:string
		 @Input() run:any

2. 把整个父组件传给子组件

将整个父组件传递给子组件
		<app-header [parent]="this"></app-header>

子组件中引入 Input 装饰器
	 	import { Component, OnInit, Input} from '@angular/core'
	 	
子组件通过 Input 装饰器获取整个父组件
		@Input parent:any
		
子组件中获取父组件的属性,执行父组件的方法
		console.log(this.parent.title)
		this.parent.run()

3. 父组件获取子组件的属性,调用子组件的方法

	见上一节 ViewChild 的用法

4. 通过 Output 和 EventEmitter 实现父子组件的通信

子组件中引入 Output 装饰器和 EventEmitter
		import { Component, OnInit, Output, EventEmitter } from '@angular/core';

子组件中通过 Output 装饰器定义一个广播因子 outer,子组件触发自身方法将广播因子播散出去
		@Output() private outer:any = new EventEmitter()
		sentToParent(){
	    	this.outer.emit('我是子组件的数据')
	 	}

父组件中捕获广播因子,触发父组件自身的方法 run,$event 作为传递的参数
		<app-news (outer)="run($event)"></app-news>  (子组件标签)
		
		run(e:any){
			console.log(e)  // e: 我是子组件的数据
	  	}

5. 非父子组件之间的通信

1. 可以通过服务的方式
2. 可以通过 localStorage 的方式

十四 Angular 中的生命周期函数

生命周期函数通常的讲就是组件创建、组件更新、组件销毁的时候会触发的一系列方法

注: 构造函数不是生命周期函数,构造函数中除了使用简单的值对局部变量进行初始化之外,什么都不应该做,构造函数在生命周期函数之前调用

组件内的生命周期函数

*  ngOnChanges()  主要是用在父子组件传值中,父组件向子组件传值的时候 以及 父组件改变传值的数据的时候会触发该函数

*  ngOnInit()  一般用来请求数据

ngDoCheck()  

ngAfterContentInit()  组件渲染完成之后触发

ngAfterContentChecked()

*  ngAfterViewInit()  在该函数中一般进行DOM操作

ngAfterViewChecked()

*  ngOnDestroy()  组件销毁时触发该函数

十五 Rxjs 异步数据流编程基础

Rxjs 是 ReactiveX 编程理念的JavaScript 版本。ReactiveX 来自微软,它是一种针对异步数据流的编程。简单的说,它将一切数据,包括 HTTP 请求,DOM 事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使我们能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现我们所需的功能。
Rxjs 是一种针对异步数据流编程工具,或者叫响应式扩展编程,目标就是异步编程。

1. 如何实现?

// 引入 Observable 
import { Observable } from 'rxjs'

// 实现方式
testRxjs(){
  let stream = new Observable(observer=>{
    setTimeout(()=>{
      let name = 'cty'
      observer.next(name) // 请求成功
      // observer.error('失败') // 请求失败
    }, 3000)
  })

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

2. Rxjs 取消订阅

Promise 的动作是无法撤回的,Rxjs 不一样,动作可以通过 unsbscribe() 方法中途撤回,而且 Observable 在内部做了智能的处理
testRxjs(){
  let stream = new Observable(observer=>{
    setTimeout(()=>{
      let name = 'cty'
      observer.next(name) // 请求成功
      // observer.error('失败') // 请求失败
    }, 3000)
  })

  let d = stream.subscribe((data)=>{
    console.log(data)
  })

  // 一秒之后取消订阅,阻止方法的继续执行
  setTimeout(() => {
    d.unsubscribe()
    console.log('已取消')
  }, 1000);
}

3. Rxjs 订阅之后多次执行

这是 Promise 做不到的,对于 Promise 来说,最终结果要么 resolve 要么 reject,而且都只能触发一次
如果在同一个 Promise 对象上多次调用 resolve 方法
则会抛出异常。而 Observable 不一样,它可以不断触发下一个值
// 每隔一秒触发一次 console.log(data)
testRxjs(){
    let stream = new Observable(observer=>{
      setInterval(()=>{
        let name = 'cty'
        observer.next(name) // 请求成功
        // observer.error('失败') // 请求失败
      }, 1000)
    })

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

4. Rxjs 使用工具方法对返回的数据进行处理

// 引入 Observable 和 相关的工具方法
import { Observable } from 'rxjs';
import { filter, map } from 'rxjs/operators';

testRxjs(){
    let count:number = 0
    let stream = new Observable(observer=>{
      setInterval(()=>{
        count++
        observer.next(count) // 请求成功
        // observer.error('失败') // 请求失败
      }, 1000)
    })

    stream.pipe(
      filter((val:any)=>val % 2 == 0),
      map((val:any)=>Number(val)*2)
    )
    .subscribe( (data:any) => {
      console.log(data)
    })
  }
// 输出 4  8  12  ...

十六 Angular 中的数据交互

1. Angular get 请求数据

① 在 app.module.ts 中引入 HttpClientModule 并注入
import { HttpClientModule } from '@angular/common/http'
...
imports: [  /* 配置当前模块运行依赖的其他模块 */
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
② 在用到的地方引入 HttpClient 并在构造函数中声明
import { HttpClient } from '@angular/common/http'
...
constructor(public http:HttpClient) { }
③ 通过 this.http.get(api).subscribe((res)=>{console.log(res)}) 处理数据
getData(){
  let api:any = 'http://a.itying.com/api/productlist'
  this.http.get(api).subscribe((res:any)=>{
    console.log(res)
  })
}

2. Angular post 提交数据(可能有跨域的问题)

① 在 app.module.ts 中引入 HttpClientModule 并注入
import { HttpClientModule } from '@angular/common/http'
...
imports: [  /* 配置当前模块运行依赖的其他模块 */
    BrowserModule,
    AppRoutingModule,
    FormsModule,
    HttpClientModule
  ],
② 在用到的地方引入 HttpClient 和 HttpHeaders 并在构造函数中声明 HttpClient
import { HttpClient, HttpHeaders } from '@angular/common/http'
...
constructor(public http:HttpClient) { }
③ 提交数据
doLogin(){
   consthttpOptions:object = {
     headers: new HttpHeaders({ 'Content-Type': 'application/json'})
   }

   let api:any = 'http://127.0.0.1:3000/dologin'

   let data:any = {'username': 'cty', 'age': 20}

   this.http.post(api, data, httpOptions).subscribe((response)=>{
     console.log(response)
   })
 }

3. Angular Jsonp 请求数据(跨域的一种解决方案)

① 在 app.module.ts 中引入 HttpClientModule, HttpClientJsonpModule 并注入
import { HttpClientModule, HttpClientJsonpModule  } from '@angular/common/http'
...
imports: [  /* 配置当前模块运行依赖的其他模块 */
   BrowserModule,
   AppRoutingModule,
   FormsModule,
   HttpClientModule,
   HttpClientJsonpModule
 ],
② 在用到的地方引入 HttpClient 和 HttpHeaders 并在构造函数中声明 HttpClient
import { HttpClient } from '@angular/common/http'
...
constructor(public http:HttpClient) { }
③ 提交数据
getJsonpData(){
    // jsonp请求,服务器必须得支持jsonp
    /*
    'http://a.itying.com/api/productlist?callback=xxx'
    'http://a.itying.com/api/productlist?cb=xxx'
    */
    let api:any = 'http://a.itying.com/api/productlist'

    this.http.jsonp(api, 'callback').subscribe((res:any)=>{
      console.log(res)
    })
  }

4. Angular 中使用第三方模块 axios 请求数据

① 安装 axios 模块
npm install axios
② 引入 axios 模块
import axios from 'axios'
③ 使用 axios 
getAxiosData(){
    let api:any = 'http://a.itying.com/api/productlist'

    let stream:any = new Observable(subscriber=>{
      axios.get(api).then((res:any)=>{
        subscriber.next(res)
      }).catch((err)=>{
        subscriber.error('err')
      })
    })

    stream.subscribe((res:any)=>{
      console.log(res)
    })
  }

十七 Angular 中的路由

路由就是根据不同的 url 地址,动态的让根组件挂载其他组件来实现一个单页面应用

1. Angular 路由基础

① 在 app-routing.module.ts 中引入组件,并编写路由路径以及路由路径对应的组件
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';

// 引入组件
import { HomeComponent } from './components/home/home.component';
import { NewsComponent } from './components/news/news.component';

// 编写路由路径以及路径对应的组件
const routes: Routes = [
  {path: 'home', component: HomeComponent},
  {path: 'news', component: NewsComponent},
  // 匹配不到路由的时候加载的组件 或者跳转的路由 默认的路由
  {path: '**', redirectTo: 'home'}
];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }
② 路由组件将动态加载到 <router-outlet></router-outlet> 中,通过 routerLink 映射到对应的路由中
	routerLinkActive="active" 调整路由选种样式 (.active{ color : red; })
<header class="header">
    <a [routerLink]="['/home']" routerLinkActive="active">Home</a>
    <button routerLink='/news' routerLinkActive="active">News</button>
</header>
<router-outlet></router-outlet>

2. Angular 路由跳转传值

2.1 get 传值

① 跳转时添加 [queryParams]="参数"
<div [routerLink]="['/home']" routerLinkActive="active" [queryParams]="{aid: 'home'}">Home</div>
<div routerLink='/news' routerLinkActive="active" [queryParams]="{cty: 'news'}">News</div>
② 组件接收
// 引入 ActivatedRoute 模块
import { ActivatedRoute } from '@angular/router';
...
// 构造函数中声明 route
constructor(public route: ActivatedRoute) {}
...
// 方法中获取 传过来的参数
this.route.queryParams.subscribe((params:any)=>{
  console.log(params)
})

2.2 动态路由

① 配置动态路由,在路径后面添加参数,参数为 cty
const routes: Routes = [
  {path: 'home', component: HomeComponent},
  {path: 'news/:cty', component: NewsComponent},
  // 匹配不到路由的时候加载的组件 或者跳转的路由 默认的路由
  {path: '**', redirectTo: 'home'}
];
② 跳转时给参数赋值 ,'333' 就是参数值
<div [routerLink]="['/news/', '3333']" routerLinkActive="active">News</div>
③ 组件接收
// 引入 ActivatedRoute 模块
import { ActivatedRoute } from '@angular/router';
...
// 构造函数中声明 route
constructor(public route: ActivatedRoute) {}
...
// 方法中获取 传过来的参数
this.route.params.subscribe((data:any)=>{
  console.log(data)
})

3. 在业务逻辑里面实现路由的跳转(JS 实现)

3.1 get 传值的 JS 跳转

① 引入 Router,NavigationExtras模块
import { Router, NavigationExtras  } from '@angular/router';
② 在构造函数中声明 router
constructor(public router: Router) { }
③ 跳转路由
let queryParams: NavigationExtras = {
  queryParams: {cty: 25}
}
this.router.navigate(['/home/'], queryParams)

3.2 动态路由的 JS 跳转

① 引入 Router 模块
import { Router } from '@angular/router';
② 在构造函数中声明 router
constructor(public router: Router) { }
③ 跳转路由
// 数组中第二个元素是动态路由的参数值,普通路由不用写第二个元素
this.router.navigate(['/news/', '12333'])
this.router.navigate(['/home'])

4. 父子路由(嵌套路由)

① 在 app-routing.module.ts 中配置父子路由
const routes: Routes = [
  {
    path: 'home', 
    component: HomeComponent,
    children: [
      {
        path: 'setting', 
        component: SettingComponent,
      },
      {
        path: 'more', 
        component: MoreComponent,
      },
      // 配置默认路由
      {path: '**', redirectTo: 'setting'}
    ]
  },
  {path: 'news/:cty', component: NewsComponent},
  // 匹配不到路由的时候加载的组件 或者跳转的路由 默认的路由
  {path: '**', redirectTo: 'home'}
];
② 模板中编写路由跳转 以及映射路由
<div class="home">
    <div class="left">
        <div class="left-route" [routerLink]="['/home/setting']">设置</div>
        <div class="left-route" [routerLink]="['/home/more']">更多</div>
    </div>
    <div class="right">
        <router-outlet></router-outlet>
    </div>
</div>
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值