因工作需要学习angular ,特此总结一下~
一、angular安装
1、安装前准备工作:
1.1、安装 nodejs
安装 angular 的计算机上面必须安装最新的 nodejs--注意安装 nodejs 稳定版本
2、使用 npm/cnpm 命令安装 angular/cli (只需要安装一次)
npm install -g @angular/cli 或者 cnpm install -g @angular/cli
二、angular创建项目
1、ng new 项目名称
例如 ng new angulardemo
如果要跳过 npm i 安装:
image.pngng new angulardemo --skip-install
2、运行项目
cd angulardemo
ng serve --open
3、目录解构分析
image.png
三、app.module.ts、组件分析
1、app.module.ts
Angular 应用是模块化的,它拥有自己的模块化系统,称作 NgModule。 一个 NgModule 就是一个容器,用于存放一些内聚的代码块,这些代码块专注于某个应用领域、某个工作流或一组紧密相关的功能。 它可以包含一些组件、服务提供商或其它代码文件,其作用域由包含它们的 NgModule 定义。 它还可以导入一些由其它模块中导出的功能,并导出一些指定的功能供其它 NgModule 使用。
/*这个文件是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 { HomeComponent } from './components/home/home.component';
import { HeaderComponent } from './components/header/header.component';
/*@NgModule装饰器, @NgModule接受一个元数据对象,告诉 Angular 如何编译和启动应用*/
@NgModule({
declarations: [ /*配置当前项目运行的的组件*/
AppComponent, NewsComponent, HomeComponent, HeaderComponent
],
imports: [ /*配置当前模块运行依赖的其他模块*/
BrowserModule
],
providers: [], /*配置项目所需要的服务*/
bootstrap: [AppComponent] /* 指定应用的主视图(称为根组件) 通过引导根AppModule来启动应用 ,这里一般写的是根组件*/
})
//根模块不需要导出任何东西, 因为其它组件不需要导入根模块
export class AppModule { }
2、自定义组件
创建组件:
ng g component components/header
组件内容解析
import { Component, OnInit } from '@angular/core'; /* 引入angular核心 */
@Component({
selector: 'app-header', /* 组件名称 */
templateUrl: './header.component.html', /* html模版 */
styleUrls: ['./header.component.scss'] /* css样式 */
})
export class HeaderComponent implements OnInit { /* 实现接口 */
constructor() { } /* 构造函数 */
ngOnInit() { /* 初始化加载时执行的生命周期函数 */
}
}
使用组件(在html文件中)
<app-header></app-header>
四、Angular 绑定数据
1、 数据文本绑定 {{ }}
<h1>
{{title}}
</h1>
<div>
1+1={{1+1}}
</div>
2、绑定 html
public content="<h2>我是一个html标签</h2>";
<div [innerHTML]="content"></div>
3.绑定属性
<div [id]="id" [title]="msg">调试工具看看我的属性</div>
4、数据循环 *ngFor
(1) *ngFor 普通循环
public userlist:any[]=[{
username:'张三',
age:20
},{
username:'李四',
age:21
},
{
username:'王五',
age:40
}];
<ul>
<li *ngFor="let item of userlist">
{{item.username}}
</li>
</ul>
(2)循环的时候设置 key
<ul>
<li *ngFor="let item of userlist;let i = index;">
{{item.username}} --{{i}}
</li>
</ul>
5、条件判断 *ngIf
<p *ngIf="userlist.length > 3">这是 ngIF 判断是否显示</p>
6、*ngSwitch
<ul [ngSwitch]="num">
<li *ngSwitchCase="1">ok</li>
<li *ngSwitchCase="2">未完成</li>
<li *ngSwitchCase="3">无效字段</li>
</ul>
7、执行事件 (click)=”getData()”
<button class="button" (click)="getData()">
点击按钮触发事件
</button>
<button class="button" (click)="setData()">
点击按钮设置数据
</button>
getData(){ /*自定义方法获取数据*/
//获取
alert(this.msg);
}
setData(){
//设置值
this.msg='这是设置的值';
}
8、表单事件
<input type="text" (keyup)="keyUpFn($event)"/>
keyUpFn(e){
console.log(e);
if(e.keyCode == 13){
console.log('11111')
};
}
9、双向数据绑定
引入:FormsModule
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms'; //引入:FormsModule
@NgModule({
declarations: [
AppComponent,
],
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
<input type="text" [(ngModel)]="inputValue"/>
{{inputValue}}
10、[ngClass]、[ngStyle]
(1)[ngClass]
<div [ngClass]="{'red': true, 'blue': false}">
这是一个 div
</div>
public flag=false;
<div [ngClass]="{'red': flag, 'blue': !flag}">
这是一个 div
</div>
public arr = [1, 3, 4, 5, 6];
<ul>
<li *ngFor="let item of arr, let i = index">
<span [ngClass]="{'red': i==0}">{{item}}</span>
</li>
</ul>
(2)[ngStyle]
public attr='red';
<div [ngStyle]="{'background-color':'green'}">你好 ngStyle</div>
<div [ngStyle]="{'background-color':attr}">你好 ngStyle</div>
11、管道[官方文档]
public today=new Date();
<p>{{today | date:'yyyy-MM-dd HH:mm:ss' }}</p>
五、服务[官方文档]
1.服务是一个广义的概念,它包括应用所需的任何值、函数或特性。狭义的服务是一个明确定义了用途的类。它应该做一些具体的事,并做好。
2.Angular 把组件和服务区分开,以提高模块性和复用性。 通过把组件中和视图有关的功能与其他类型的处理分离开,你可以让组件类更加精简、高效
image.png
1、创建服务
ng g service services/storage
2、app.module.ts 里面引入创建的服务
mport { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
//引入表单相关的模块 才可以用双休数据绑定
import { FormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
//引入并且配置服务
import { StorageService } from './services/storage.service';
@NgModule({
declarations: [
AppComponent,
SearchComponent,
TodolistComponent
],
imports: [
BrowserModule,
FormsModule
],
providers: [StorageService], //NgModule 里面的 providers 里面依赖注入服务
bootstrap: [AppComponent]
})
export class AppModule { }
3、使用的页面引入服务,注册服务
import { Component, OnInit } from '@angular/core';
//引入服务
import { StorageService } from '../../services/storage.service';
@Component({
selector: 'app-list',
templateUrl: './list.component.html',
styleUrls: ['./list.component.scss']
})
export class TodolistComponent implements OnInit {
constructor(public storage:StorageService) { //注册服务
}
ngOnInit() {
}
}
4、使用
ngOnInit() {
var list:any=this.storage.get('tlist');
if(list){
this.list=list;
}
}
六、动画
(1)Angular 中的 dom 操作(原生 js)
ngAfterViewInit(){ //angular 中操作dom要在这个生命周期钩子函数中
var boxDom:any=document.getElementById('box');
boxDom.style.color='red';
}
(2)Angular 中的 dom 操作(ViewChild)
<div #myBox>
我是一个dom节点
</div>
//在业务逻辑里面引入ViewChild
import { Component, OnInit,ViewChild} from '@angular/core';
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {
//获取dom节点
@ViewChild('myBox') myBox:any;
constructor() { }
ngOnInit() {
}
//ngAfterViewInit生命周期函数里面获取dom
ngAfterViewInit(): void {
console.log(this.myBox.nativeElement);
this.myBox.nativeElement.style.width='100px';
this.myBox.nativeElement.style.height='100px';
this.myBox.nativeElement.style.background='red';
console.log(this.myBox.nativeElement.innerHTML);
}
}
补充: 父子组件中通过 ViewChild 调用子组件的方法
(1)引入子组件
<app-header #header></app-header>
<button (click)="getChildRun()">获取子组件的方法</button>
(2)关联起来
import { Component, OnInit,ViewChild} from '@angular/core';
@Component({
selector: 'app-news',
templateUrl: './news.component.html',
styleUrls: ['./news.component.scss']
})
export class NewsComponent implements OnInit {
//获取dom节点
@ViewChild('myBox') myBox:any;
//获取一个组件
@ViewChild('header') header:any;
constructor() { }
ngOnInit() {
}
getChildRun(){
//调用子组件里面的方法
this.header.run();
}
}
七、Angular 父子组件以及组件之间通讯
1、父组件给子组件传值-@input
(1)父组件调用子组件的时候传入数据
<app-header [msg]="msg"></app-header>
(2)子组件引入 Input 模块
import { Component, OnInit,Input} from '@angular/core';
(3)子组件中 @Input 接收父组件传过来的数据
export class HeaderComponent implements OnInit {
@Input() msg:string
constructor() { }
ngOnInit() {
}
}
(4)子组件中使用父组件的数据
<h2>这是头部组件--{{msg}}</h2>
2、子组件通过@Output 触发父组件的方法
(1)子组件引入 Output 和 EventEmitter
import { Component, OnInit,Output,EventEmitter } from '@angular/core';
(2)子组件中实例化 EventEmitter
@Output() private outer=new EventEmitter<string>();
/*用 EventEmitter 和 output 装饰器配合使用 <string>指定类型变量
(3)子组件通过 EventEmitter 对象 outer 实例广播数据
sendParent(){
// alert('zhixing');
this.outer.emit('msg from child')
}
(4).父组件调用子组件的时候,定义接收事件 , outer 就是子组件的 EventEmitter 对象 outer
<app-header (outer)="runParent($event)"></app-head
(5)父组件接收到数据会调用自己的 runParent 方法,这个时候就能拿到子组件的数据
//接收子组件传递过来的数据
runParent(msg:string){
console.log(msg);
}
八、Angular 中的生命周期函数
1、ngOnChanges()
当 Angular(重新)设置数据绑定输入属性时响应。 该方法接受当前和上一属性值的 SimpleChanges 对象当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 ngOnInit() 之前。
2、ngOnInit()
在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。
在第一轮 ngOnChanges() 完成之后调用,只调用一次。
使用 ngOnInit() 有两个原因:
1、在构造函数之后马上执行复杂的初始化逻辑
2、在 Angular 设置完输入属性之后,对该组件进行准备。
有经验的开发者会认同组件的构建应该很便宜和安全。
3、ngDoCheck()
检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。在每个 Angular 变更检测周期中调用,ngOnChanges() 和 ngOnInit() 之后
4、ngAfterContentInit()
当把内容投影进组件之后调用。第一次 ngDoCheck() 之后调用,只调用一次。
5、ngAfterContentChecked()
每次完成被投影组件内容的变更检测之后调用。ngAfterContentInit() 和每次 ngDoCheck() 之后调用。
6、ngAfterViewInit()
初始化完组件视图及其子视图之后调用。第 一次 ngAfterContentChecked() 之后调用,只调用一次。
7、ngAfterViewChecked()
每次做完组件视图和子视图的变更检测之后调用。ngAfterViewInit()和每次 ngAfterContentChecked() 之后调用
8、ngOnDestroy()
当 Angular 每次销毁指令/组件之前调用并清扫。在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。在 Angular 销毁指令/组件之前调用
import { Component,Input} from '@angular/core';
@Component({
selector: 'app-lifecycle',
templateUrl: './lifecycle.component.html',
styleUrls: ['./lifecycle.component.scss']
})
export class LifecycleComponent{
@Input('title') title:string;
public msg:string='我是一个生命周期演示';
public userinfo:string='';
public oldUserinfo:string='';
constructor() {
console.log('00构造函数执行了---除了使用简单的值对局部变量进行初始化之外,什么都不应该做')
}
ngOnChanges() {
console.log('01ngOnChages执行了---当被绑定的输入属性的值发生变化时调用(父子组件传值的时候会触发)');
}
ngOnInit() {
console.log('02ngOnInit执行了--- 请求数据一般放在这个里面');
}
ngDoCheck() {
//写一些自定义的操作
console.log('03ngDoCheck执行了---检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应');
if(this.userinfo!==this.oldUserinfo){
console.log(`你从${this.oldUserinfo}改成${this.userinfo}`);
this.oldUserinfo = this.userinfo;
}else{
console.log("数据没有变化");
}
}
ngAfterContentInit() {
console.log('04ngAfterContentInit执行了---当把内容投影进组件之后调用');
}
ngAfterContentChecked() {
console.log('05ngAfterContentChecked执行了---每次完成被投影组件内容的变更检测之后调用');
}
ngAfterViewInit(): void {
console.log('06 ngAfterViewInit执行了----初始化完组件视图及其子视图之后调用(dom操作放在这个里面)');
}
ngAfterViewChecked() {
console.log('07ngAfterViewChecked执行了----每次做完组件视图和子视图的变更检测之后调用');
}
ngOnDestroy() {
console.log('08ngOnDestroy执行了····');
}
//自定义方法
changeMsg(){
this.msg="数据改变了";
}
}
运行后结果:
image.png
再次进入页面: image.png
只会执行ngDoCheck() , ngAfterContentChecked() , ngAfterViewChecked()
九、Rxjs
它是一种针对异步数据流的编程。简单来说,它将一切数据,包括 HTTP 请求,DOM 事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能
1、RxJS 处理异步:
import {Observable} from 'rxjs';
let stream = new Observable(observer => {
setTimeout(() => {
observer.next('observable timeout');
}, 2000);
});
stream.subscribe(value => console.log(value));
从上面例子我们感觉Promise 和 RxJS 的用法基本相似。其实Rxjs相比Promise 要强大很多。
比如 Rxjs 中可以中途撤回、Rxjs 可以发射多个值、Rxjs 提供了多种工具函数等等。
2、Rxjs unsubscribe 取消订阅
Promise 的创建之后,动作是无法撤回的。
Observable 不一样,动作可以通过unsbscribe() 方法中途撤回,而且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);
3、Rxjs 订阅后多次执行
我们想让异步里面的方法多次执行 , promise做不到
let promise = new Promise(resolve => {
setInterval(() => {
resolve('---promise setInterval---');
}, 2000);
});
promise.then(value => console.log(value));
但是Rxjs可以
let stream = new Observable<number>(observer => {
let count = 0;
setInterval(() => {
observer.next(count++);
}, 1000);
});
stream.subscribe(value => console.log("Observable>"+value));
4、使用 Rxjs 的工具函数map filter
import {Observable} from 'rxjs';
let stream= new Observable<any>(observer => {
let count = 0;
setInterval(() => {
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));
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`));
6、Rxjs6.x 的变化以及使用
RXJS6 改变了包的结构,主要变化在 import 方式和 operator 上面以及使用 pipe()
import {Observable} from 'rxjs';
import {map,filter} from 'rxjs/operators';
let stream= new Observable<any>(observer => {
let count = 0;
setInterval(() => {
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));Ï
十、Angular 中的数据交互
1、Angular get 请求数据
(1)在 app.module.ts 中引入 HttpClientModule 并注入
import {HttpClientModule} from '@angular/common/http';
imports: [
BrowserModule,
HttpClientModule
]
(2)在用到的地方引入 HttpClient 并在构造函数声明
import {HttpClient} from "@angular/common/http";
constructor(public http:HttpClient) { }
(3)get 请求数据
var api = "http://xxxxxxxxxxxx";
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
]
(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:'张三',age:'20'},httpOptions).subscribe(response => {
console.log(response);
});
3、Angular Jsonp 请求数据
(1)在 app.module.ts 中引入 HttpClientModule、HttpClientJsonpModule 并注入
import {HttpClientModule,HttpClientJsonpModule} from '@angular/common/http';
imports: [
BrowserModule,
HttpClientModule,
HttpClientJsonpModule
]
(2)在用到的地方引入 HttpClient 并在构造函数声明
import {HttpClient} from "@angular/common/http";
constructor(public http:HttpClient) { }
(3)jsonp 请求数据
var api = "http://a.itying.com/api/productlist";
this.http.jsonp(api,'callback').subscribe(response => {
console.log(response);
});
4、Angular 中使用第三方模块 axios 请求数据(无比怀念axios!!!!!)
(1)安装 axios
cnpm install axios --save
(2)用到的地方引入 axios
import axios from 'axios';
(3)用它
axios.get('/user?ID=12345')
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
.then(function () {
// always executed
})
十一、路由
1、找到 app-routing.module.ts 配置路由
引入组件
import { HomeComponent } from './home/home.component';
import { NewsComponent } from './news/news.component';
import { NewscontentComponent } from './newscontent/newscontent.component';
配置路由
const routes: Routes = [
{path: 'home', component: HomeComponent},
{path: 'news', component: NewsComponent},
{path: 'newscontent/:id', component: NewscontentComponent},
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
}
]
空路径('')表示应用的默认路径,当 URL 为空时就会访问那里,因此它通常会作为起点。 这个默认路由会重定向到 URL /home,并显示 HomeComponent。
找到 app.component.html 根组件模板,配置 router-outlet 显示动态加载的路由
<h1>
<a routerLink="/home">首页</a>
<a routerLink="/news">新闻</a>
</h1>
<router-outlet></router-outlet>
2、**通配符
{ path: '**', component: PageNotFoundComponent }
最后一个路由中的 ** 路径是一个通配符。当所请求的 URL 不匹配前面定义的路由表中的任何路径时,路由器就会选择此路由。 这个特性可用于显示“404 - Not Found”页,或自动重定向到其它路由。
3、routerLinkActive 设 置 routerLink 默认选中路由
<h1>
<a [routerLink]="[ '/home' ]" routerLinkActive="active">首页</a>
<a [routerLink]="[ '/news' ]" routerLinkActive="active">新闻</a>
</h1>
.active{
color:red;
}
4、动态路由
配置动态路由
const routes: Routes = [
{path: 'home', component: HomeComponent},
{path: 'news', component: NewsComponent},
{path: 'newscontent/:id', component: NewscontentComponent},
{
path: '',
redirectTo: '/home',
pathMatch: 'full'
}
];
跳转传值
<a [routerLink]="[ '/newscontent/',aid]">跳转到详情</a>
<a routerLink="/newscontent/{{aid}}">跳转到详情</a>
获取动态路由的值
import { ActivatedRoute} from '@angular/router';
constructor( private route: ActivatedRoute) { }
ngOnInit() {
console.log(this.route.params);
this.route.params.subscribe(data=>this.id=data.id);
}
5、动态路由的 js 跳转
引入
import { Router } from '@angular/router';
初始化
export class HomeComponent implements OnInit {
constructor(private router: Router) { }
ngOnInit() { }
goNews(){
// this.router.navigate(['/news', hero.id]);
this.router.navigate(['/news']);
//传值
this.router.navigate(['/news', hero.id]);
}
}
6、路由 get 传值 js 跳转
引入 NavigationExtras
import { Router ,NavigationExtras} from '@angular/router';
定义一个 goNewsContent 方法执行跳转,用 NavigationExtras 配置传参
goNewsContent(){
let navigationExtras: NavigationExtras = {
queryParams: { 'session_id': '123' },
fragment: 'anchor'
};
this.router.navigate(['/news'],navigationExtras);
}
获取 get 传值
constructor(private route: ActivatedRoute) {
console.log(this.route.queryParams);
}
7、父子路由
创建组件引入组件
import { NewsaddComponent } from './components/newsadd/newsadd.component';
import { NewslistComponent } from './components/newslist/newslist.component';
配置路由
{
path: 'news',
component:NewsComponent,
children: [
{
path:'newslist',
component:NewslistComponent
},
{
path:'newsadd',
component:NewsaddComponent
}
]
}
父组件中定义 router-outlet
<router-outlet></router-outlet>
十二、Angular 中自定义模块
1、Angular 内置模块
image.png
2、Angular 自定义模块
当我们项目比较小的时候可以不用自定义模块。但是当我们项目非常庞大的时候把所有的组
件都挂载到根模块里面不是特别合适。所以这个时候我们就可以自定义模块来组织我们的项
目。并且通过 Angular 自定义模块可以实现路由的懒加载。
image.pngng g module mymodule
创建模块:
ng g module module/user --routing
ng g module module/article --routing
ng g module module/product --routing
创建组件:
ng g component module/user
ng g component module/user/components/profile
ng g component module/user/components/order
ng g component module/article
ng g component module/article/components/articlelist
ng g component module/article/components/info
ng g component module/product
ng g component module/product/components/plist
ng g component module/product/components/pinfo
配置懒加载
import { HomeComponent } from './components/home/home.component';
const routes: Routes = [
{
path:'',component : HomeComponent
},
{
path:'user',loadChildren : './usermodule/usermodule.module#UsermoduleModule'
}
];
最后我只想说一句 vue相比于angular真的太简单了!!
以后在工作中遇到的问题会持续更新在简书~
在学习angular的朋友一起共勉吧~~
网友评论