Angualr是谷歌开发的一款开源的web前端框架,诞生于2009年,由Misko Hevery 等人创建,后为Google所收购。是一款优秀的前端JS框架,已经被用于Google 的多款产品当中。
根据项目数统计angular (1.x 、2.x 、 4.x、5.x、6.x、7.x 、8.x、9.x)是现在网上使用量最大的框架。
Angular基于TypeScript
,和react、vue相比 Angular更适合中大型企业级项目。
目前2019年12月25日angular最新版本 angular9.x。根据官方介绍,Angular每过几个月就会更新一个版本。Angular2.x以后所有的Angular版本用法都是一样的
,此教程同样适用于Angular7.x 、 Angular8.x、Angular9.x以及未来的其它版本…
注意:学习Angular需TypeScript基础
npm install -g @angular/cli
ng v
,查看版本注意:angular Cli对node版本要求比较严格,注意警告提示的node版本
创建项目
ng new 项目名
:如ng new testObj
Would you like to add Angular routing? //是否安装angular路由
Mhich stylesheet fornat would you like to use?//选择何种css处理器
css
scss
sAss
LESS
Stglus
安装依赖
npm i
运行项目
ng serve --open
IE8不支持angular项目
app //放置组件和根模块的文件夹
assets //静态资源文件夹
environments //环境相关文件夹
.browserslistrc //浏览器配置支持文件
favicon.ico //网页图标
index.html //入口文件
karma.conf.js //端对端测试文件
main.js //项目入口文件
polyfill.js //项目填充库
styles.css //公共样式文件,文件类型由创建项目时决定
test.ts //测试入口文件
package.json //npm配置文件
终端执行ng g
查看可新建文件类型
ng g 类型名称 指定目录
#例子:创建新组件至app下方components中的news文件夹
ng g component components/news
组件路径视乎默认app文件夹为根目录
import { Component, OnInit } from '@angular/core';
@Component({
selector: '...', //使用这个组件的名称
templateUrl: '...', //这个组件的html
styleUrls: ['...'] //这个组件的css
})
//语法参照typescript中的类
export class NewsComponent implements OnInit {
public newsTitle = "每日新闻" //
msg:string = '今日气温较高' //不加属性修饰符typescript会默认属性为public
//定义数据是应指定数据类型(typescript规范
constructor() { } //构造函数
ngOnInit(): void {
}
}
<h2>我是新闻组件h2>
<ul>
<li>{{newsTitle}}li>
ul>
鼠标hover,演示属性动态绑定
-
{{item}}
index:{{i}}
是否为奇数:{{odd}}
是否为偶数:{{even}}
是否为第一个:{{f}}
是否为最后一个:{{l}}
// 不用写相对图片目录,默认从assets文件夹查找
public imgSrc ='assets/image/icon-yellow_05.png'
为true的时候我显示
为true的时候我显示
为false的时候我显示
<span [ngSwitch]="stateNum">
<p *ngSwitchCase=1>
1表示失败
p>
<p *ngSwitchCase=2>
2表示成功
p>
<p *ngSwitchDefault>
默认情况
p>
span>
我演示ngClass
我在演示ngStyle
点我!
{{str}}
ts文件
...
export class HeaderComponent implements OnInit {
...
public str = 'FBI open door!!!'
...
constructor() { }
ngOnInit(): void {
}
// 自定义方法
run(e:any):void{
alert('跑呀!!!')
// 改变数据
this.str = 'FBI incoming !!!'
console.log(e)
}
// 参数必须指定类型
inputFn(e:any):void{
console.log(e)
}
}
...
// FormsModule实现双向绑定
import { FormsModule } from '@angular/forms';
@NgModule({
declarations: [ //配置当前项目运行的组件
...
],
imports: [ //配置当前模块运行依赖的其他模块
....
FormsModule
],
...
})
...
{{bdstr}}
管道(pipe),作用和用法类似Vue中的过滤器(filter)
{{'Str' | uppercase}}
//转换成大写
{{'Str' | lowercase}}
//转换成小写
{{new Date().getTime() | date:'yyyy-MM-dd HH:mm:ss' }}
使用ng g pipe 放置目录/管道名
创建
例如:在app下的pipe下创建mydemo管道
ng g pipe pipe/mydemo
下面为管道ts文件内容
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
// 定义引用管道名
name: 'mydemo'
})
export class MydemoPipe implements PipeTransform {
// transform(value: unknown, ...args: unknown[]): unknown {
// return null;
// }
// 自定义管道函数(函数名固定为transform)
transform(value: string): string {
if(!value) return value;
if(typeof value !== 'string') {
throw new Error('Invalid pipe argument for WelcomePipe');
}
return "Welcome to " + value;
}
}
app.module.ts
中引入管道
// 引入管道
import { MydemoPipe } from './pipe/mydemo.pipe';
//配置管道
@NgModule({
declarations: [ //配置当前项目运行的组件
MydemoPipe
],
)}
使用自定义管道
{{ '天津' | mydemo }}
存放公共方法或属性,可创建多个服务,服务之间可相互调用
ng g service 指定目录/服务名称
感觉类似Vue中的VueX?
在app.module.ts
中
// 引入服务
//MyserviceService为myservice.service中暴露出的类名
import { MyserviceService } from './services/myservice.service'
@NgModule({
declarations: [ //配置当前项目运行的组件
...
],
imports: [ //配置当前模块运行依赖的其他模块
...
],
providers: [ MyserviceService ], //配置项目所需要的服务
...
})
在组件中
// 引入该组件需使用的服务
import { MyserviceService } from '../../services/myservice.service'
export class TodolistComponent implements OnInit {
...
// 初始化服务
// 依赖注入???
//public 自定义变量名:引入的服务名
constructor(public myserve:MyserviceService) {
}
ngOnInit(): void {
// 使用服务中的方法
this.myserve.show()
}
}
通过sessionStorage或localStorage实现
类似Vue中的ref ?
//在组件ts中引入ViewChild
import { Component, OnInit,ViewChild,... } from '@angular/core';
//在html中使用 #自定义名称 标识dom节点
/*
我是ViewChild绑定的div
*/
//使用ViewChild修饰器获取dom节点
export class ViewchildComponent implements OnInit {
//@ViewChild('dom上使用 # 绑定的名称') 自定义变量名:any
@ViewChild('mybox') aaa:any
constructor() { }
ngOnInit(): void {
}
ngAfterViewInit(): void {
console.log(this.aaa,'打印mybox')
}
}
//绑定子组件app-news
/*
*/
//使用子组件方法
export class ViewchildComponent implements OnInit {
//通过ViewChild获取子组件
@ViewChild('news') news:any
constructor() { }
ngOnInit(): void {
}
ngAfterViewInit(): void {
//查看子组件信息
console.log(this.news,'打印news')
// 调用子组件方法
this.news.say()
}
}
@input
类似Vue中的 props
父组件不仅可以给子组件传递数据,还可以把自己的方法以及整个父组件传递给子组件
<app-search [msg]="message" [fn]='run' [fcpn]='this'>app-search>
// 子组件中引入Input模块
import { Component, OnInit,Input } from '@angular/core';
export class SearchComponent implements OnInit {
...
// 使用Input修饰器绑定数据
@Input() msg:any
@Input() fn:any
@Input() fcpn:any
constructor() { }
ngOnInit(): void {
console.log(this.msg,'父组件传递的数据')
// 执行父组件方法
this.fn()
// console.log('执行父组件方法')
// 输出父组件
console.log(this.fcpn,'输出父组件')
}
}
有以下两种方法:
@Output
触发父组件的方法,类似Vue中的$emit
//在子组件中引入 Output,EventEmitter 模块
import { Component, OnInit,Input ,Output,EventEmitter} from '@angular/core';
export class SearchComponent implements OnInit {
...
//通过Output修饰器声明变量,接收 实例化EventEmitter
@Output() private myouter = new EventEmitter
constructor() { }
...
// 给父组件传值
doting(){
// 广播数据
console.log(111)
this.myouter.emit('我是子组件传递给父组件的数据')
}
}
<app-search (myouter)="getChild($event)">app-search>
函数名 | 描述 |
---|---|
constructor | 构造函数中除了使用简单的值对局部变量进行初始化之外,什么都不应该做。(它不是生命周期函数) |
ngOnChanges | 当Angular(重新)设置数据绑定输入属性时响应。该方法接受当前和上一属性值的SimpleChange对象。 当被绑定的输入属性值发生改变时调用,首次调用一定会发生在ngOnInit之前。 |
ngOnInit | 在Angular第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。 在第一轮ngOnChanges ()完成之后调用,只调用一次 。======使用ngOnInit 的两个原因:1、在构造函数之后马上执行复杂的初始化逻辑;2、在Angular设置完输入属性之后,对该组件进行准备。 |
ngDoCheck | 检查,在ngOnInit 执行。可以在该生命周期中对数据进行检查操作 |
ngAfterContentInit | 组件渲染之后的周期函数,当把内容投影进组件之后调用,第一次ngDoCheck 后调用,只调用一次 |
ngAfterContentChecked | 检查,和ngDoCheck 类似 |
ngAfterViewInit | 视图加载完成后调用。第一次ngAfterContentChecked ()之后调用,只调用一次 |
ngAfterViewChecked | 检查,和ngDoCheck 类似 |
ngOnDestroy | 组件销毁前调用 |
// implements后面为生命函数对应的规范,可以不引入
// 若引入则需按照其规范书写
// 引入多个时使用 , 分割
export class LifefnComponent implements OnInit {
public msg:string = ''
constructor() {
console.log('00---我是constructor构造函数')
}
ngOnChanges(): void {
console.log('01---我是 ngOnChanges 生命周期函数')
}
ngOnInit(): void {
console.log('02---我是 ngOnInit 生命周期函数')
}
ngDoCheck(): void {
console.log('03---我是 ngDoCheck 生命周期函数')
}
ngAfterContentInit(): void {
console.log('04---我是 ngAfterContentInit 生命周期函数')
}
ngAfterContentChecked(): void {
console.log('05---我是 ngAfterContentChecked 生命周期函数')
}
ngAfterViewInit(): void {
console.log('06---我是 ngAfterViewInit 生命周期函数')
}
ngAfterViewChecked(): void {
console.log('07---我是 ngAfterViewChecked 生命周期函数')
}
ngOnDestroy(): void {
console.log('08---我是 ngOnDestroy 生命周期函数')
}
}
RxJS是 Reactivex编程理念的JavaScript版本。ReactiveX来自微软,它是一种针对异步数据流的编程。简单来说,它将一切数据,包括HTTP请求,DOM事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。
RxJS是一种针对异步数据流编程工具,或者叫响应式扩展编程;可不管如何解释RxJS其目标就是异步编程,Angular引入 RxJS为了就是让异步可控、更简单。
通俗理解:RxJS主要用于异步编程,和Promise相似,但功能更加强大。
RxJS是一个第三方模块,但Angular自身已经集成了RxJS,就是为了让异步可控、更简单。
目前常见的异步编程方法:
使用方法类似
但RxJS中可以中途撤回、Rxjs可以发射多个值、Rxjs提供了多种工具函数等等。
// 在使用的文件中使用RxJS
// 引入RxJS的Observable
import { observable, Observable } from 'rxjs';
#定义函数
...
// Promise
getPromiseData(){
return new Promise((resolve,reject) => {
setTimeout(() => {
let data = {
name:'张三',
age:16
}
resolve(data)
}, 2000);
})
}
// RxJS
getRxjsData(){
return new Observable((observer) =>{
setTimeout(() => {
let data = {
name:'张三',
age:16
}
observer.next(data) //成功调用.next方法
// observer.error('出错啦') //失败调用.error方法
}, 2000);
})
}
#调用
//3. promise获取异步数据
this.myserve.getPromiseData().then((res) => {
console.log(res,'Promise')
})
// 4.RxJS获取异步数据
this.myserve.getRxjsData().subscribe((res) => {
console.log(res,'RxJS')
})
Promise创建之后,动作是无法撤回的.Observable不一样,动作可以通过unsubscribe方法中途撤回
// 5.使用unsubscribe撤回操作
// 如果异步方法还未执行,就可以撤回
let rxjsFn = this.myserve.getRxjsData()
let data2 = rxjsFn.subscribe((res) => {
console.log(data,'RxJS的subscribe值')
})
// 通过subscribe的值来取消
// 效果:一秒后取消getRxjsData的执行
setTimeout(() => {
// unsubscribe取消订阅
data2.unsubscribe()
}, 1000);//此处的延迟时间小于getRxjsData中的延迟(模拟在异步函数执行前撤回
#serve中定义
// 多次执行对比
// Promise
getPromiseDataInterval(){
return new Promise((resolve,reject) => {
setInterval(() => {
let data = {
name:'张三',
age:16
}
resolve(data)
},1000)
})
}
// RxJS
getRxjsDataInterval(){
return new Observable((observe) => {
setInterval(() =>{
let data = {
name:'张三',
age:16
}
observe.next(data)
},1000)
})
}
#引用
// 6.Promise多次执行(Promise不能做到
let p2 = this.myserve.getPromiseDataInterval()
p2.then((res) => {
console.log(res,'Promise多次执行')
})
// 7.RxJS多次执行
let r2 = this.myserve.getRxjsDataInterval()
r2.subscribe((res) => {
console.log(res,'RxJS多次执行')
})
**注意:**Angular6之后的RxJS版本为6.x,如果想在Angular6.x之前的方法使用RxJS6.x版本中的某些方法,必须安装rxjs-compat
模块才可以使用map、filter
angular6后官方使用的是RxJS6 的新特性,所以官方给出了一个可以暂时延缓我们不需要修改rsjx代码的办法。
npm install rxjs-compat
Angular6.x之后使用则不需要安装rxjs-compat
RxJS6改变了包的结构,主要变化在import方法和operator上面,以及使用pipe()
引入模块
//在使用的组件中引入模块
// 引入RxJS的map,filter工具模块
import { map,filter } from 'rxjs/operators'
使用
// 8.通过工具方法对数据进行处理
let num = this.myserve.getRxjsNumInterval()
// 在管道pipe中使用工具方法
// filter返回满足条件的值
// num.pipe(
// filter((item:any) =>{
// return item%2 == 0
// })
// ).subscribe((res) => {
// console.log(res,'-----filter')
// })
// map为变量,与ES5中类似
// num.pipe(
// map((item:any) => {
// return item * item
// })
// ).subscribe((res) => {
// console.log(res,'-----map')
// })
// 可在管道(pipe)中使用多个方法
num.pipe(
filter((item:any) => {
return item%2 ==0
}),
map((item) => {
return item * item
})
).subscribe((res) => {
console.log(res,'-----多个工具结合使用')
})
通过throttleTime
实现
//引入
import { throttleTime } from 'rxjs/operators'
//使用
let rxjsFn = this.myserve.getRxjsData()
rxjsFn.pipe(
throttleTime(1000)
).subscribe((res) => {
console.log(res)
})
Angular5.x以后的get、post和服务器交互使用的是HttpClientModule
模块
引入
//在app.moudle.ts中引入HttpClientModule模块,并进行配置
// 引入HttpClientMidule模块,实现数据交互
import { HttpClientModule } from '@angular/common/http'
...
@NgModule({
declarations: [ //配置当前项目运行的组件
....],
imports: [ //配置当前模块运行依赖的其他模块
...
HttpClientModule
],
...
})
...
组件中导入
// 在组件中引入HttpClient模块,可以借为HttpClientModule模块的一个服务
import { HttpClient } from '@angular/common/http';
声明服务并使用方法
export class NetworkComponent implements OnInit {
// 声明服务
constructor(private myhttp:HttpClient) { }
// get方法
getData(){
let url = 'http://a.itying.com/api/productlist'
//HttpClicent返回的是一个RxJS对象。使用subscribe进行调用
this.myhttp.get(url).subscribe((res) => {
console.log(res)
})
}
// post提交数据
postData(){
// 手动定义请求头
const myHttpOptions = {
headers :new HttpHeaders({'Content-Type':'application/json'})
}
this.myhttp.post('http://47.104.7.144:3001/api/adminlogin',
{"name":'ICPFAadmin',"pwd":'admin'},
// myHttpOptions
).subscribe((res) => {
console.log(res)
})
}
}
安装
npm install axios --save
引入
推荐在服务文件中引入
// 引入axios
import axios from 'axios';
export class AxiosService {
axiosGetData(){
// 返回axios,在外部调用.then方法
return axios({
url:'http://47.104.7.144:3001/api/adminlogin',
method:'post',
data:{
name:'ICPFAadmin',
pwd:'admin'
}
})
}
}
使用
// 在需要的组件中引入服务
import { AxiosService } from 'src/app/services/axios.service';
...
export class AxiosComponent implements OnInit {
// 声明服务
constructor(private myaxios:AxiosService) { }
ngOnInit(): void {
// 使用服务中的axios
this.myaxios.axiosGetData().then((res) => {
console.log(res,'axios')
})
}
}
在创建项目时选择安装路由即可新建一个包含路由的项目
若创建项目时没有安装路由,则可在app目录下新建app-routing.module.ts
路由配置文件
// 路由配置模块
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
const routes: Routes = [];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
并在app.module.ts
引入并配置
//引入路由配置文件
import { AppRoutingModule } from './app-routing.module';
...
@NgModule({
declarations: [ ... ],
imports: [ //配置当前模块运行依赖的其他模块
AppRoutingModule,
...
],
providers: [ ... ], //配置项目所需要的服务
bootstrap: [AppComponent]
})
在app.component.html
中增加
在路由文件中引入对应的组件
// 路由配置模块
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
// 引入路由需要的组件
import { NewsComponent } from './components/news/news.component';
import { TodolistComponent } from './components/todolist/todolist.component';
// 配置路由
const routes: Routes = [
{
// 路径
path:'home',
// 对应的组件
component:TodolistComponent
},
{
path:'news',
component:NewsComponent
},
// 重定向方法一
// {
// path:'',
// // 重定向
// redirectTo:'home',
// pathMatch:'full'
// }
// 重定向方法二
{
path:'**',
// 重定向
redirectTo:'news',
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
配置路由
// 动态路由传值
{
path:'router/:routedata',
component:RouterComponent
},
// get传参
// {
// path:'router',
// component:RouterComponent
// },
传递
<a [routerLink]="[ '/router', '我是数据' ]">路由传值---paramsa>
<a [routerLink]="[ '/router']" [queryParams]="{myid:1,name:'张三'}">路由传值---queryParamsa>
获取
在组件中引入ActivatedRoute
// 引入ActivatedRoute模块
import { ActivatedRoute } from '@angular/router';
...
export class RouterComponent implements OnInit {
// 声明ActivatedRoute
constructor(public myactiveroute:ActivatedRoute) { }
ngOnInit(): void {
console.log(this.myactiveroute,'当前激活路由')
//返回值是一个RxJS对象,需使用 subscribe 调用
//方法一
this.myactiveroute.params.subscribe((res) => {
console.log(res,'路由参数---params')
})
//方法二
this.myactiveroute.queryParams.subscribe((res) => {
console.log(res,'路由参数---queryParams')
})
}
}
// 引入Router
import { Router } from '@angular/router';
...
export class RoutermainComponent implements OnInit {
// 声明
constructor(public myrouter:Router) { }
ngOnInit(): void {
}
goPage(){
// 动态路由
this.myrouter.navigate(['/router','我是动态路由的数据'])
}
goHome(){
// 普通路由
this.myrouter.navigate(['/home'])
}
}
// 引入Router
// 事件跳转get路由还需引入NavigationExtras
import { Router,NavigationExtras } from '@angular/router';
export class RoutermainComponent implements OnInit {
// 声明
constructor(public myrouter:Router) { }
...
goGet(){
// Get路由
// 定义传递的数据,并将类型指定为NavigationExtras
let myqureyData:NavigationExtras = {
queryParams:{
name:'哇哈哈',
age:12
}
}
this.myrouter.navigate(['/routerget'],myqureyData)
}
}
//配置路由
{
path:'routermain',
component:RoutermainComponent,
children:[
{
path:'child',
component:RouterchildComponent
}
]
},
前往子路由