angular入門

1、Angular 介紹

Angualr 是一款來自谷歌的開源的 web 前端框架,誕生於 2009 年,由 Misko Hevery 等 人建立,後爲 Google 所收購。是一款優秀的前端 JS 框架,已經被用於 Google 的多款產品當中。javascript

  • 根據項目數統計 angular(1.x 、2.x 、4.x、5.x、6.x、7.x)是如今網上使用量最大的框架
  • Angualr 基於 TypeScriptreactvue 相比, Angular 更適合中大型企業級項目。

目前 2018 年 11 月 25 日 angular 最新版本 angular7.x。根據官方介紹,Angular 每過幾個月 就會更新一個版本。此教程一樣適用於後期更新的 Angular8.xAngular9.xcss

 
image.png

學習 Angular 必備基礎html

必備基礎:htmlcssjses6Typescript前端

2、Angular 環境搭建及建立項目

2.1 環境搭建

1. 安裝 nodejsvue

安裝 angular 的計算機上面必須安裝最新的 nodejs--注意安裝 nodejs 穩定版本java

2. 安裝 cnpmnode

npm 可能安裝失敗建議先用 npm 安裝一下 cnpm 用淘寶鏡像安裝https://npm.taobao.orgreact

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

3. 使用 npm/cnpm 命令安裝 angular/clijquery

npm install -g @angular/cli 

# 或者 cnpm install -g @angular/cli 

ng v 查看版本信息ios

 
angular cli

4. 安裝插件

 
image.png

5. 安裝chrome擴展

https://augury.angular.io/

augury查看component結構,更方便調試

 
image.png

2.2 建立項目

# 建立項目 ng new my-app cd my-app # 運行項目 ng serve --open 

2.3 目錄結構分析

 
image.png

詳情參考 https://www.angular.cn/guide/file-structure

app目錄(重點)

app目錄是咱們要編寫的代碼目錄。咱們寫的代碼都是放在這個目錄。
一個Angular程序至少須要一個模塊和一個組件。在咱們新建項目的時候命令行已經默認生成出來了

 
image.png
  • app.component.ts:這個文件表示組件,
  • 組件是Angular應用的基本構建模塊,能夠理解爲一段帶有業務邏輯和數據的Html
    咱們來看看app.component.ts中的代碼,並解釋下代碼的意義
 
app.component.ts
/*這裏是從Angular核心模塊裏面引入了component裝飾器*/ import {Component} from '@angular/core'; /*用裝飾器定義了一個組件以及組件的元數據 全部的組件都必須使用這個裝飾器來註解*/ @Component({ /*組件元數據 Angular會經過這裏面的屬性來渲染組件並執行邏輯 * selector就是css選擇器,表示這個組件能夠經過app-root來調用,index.html中有個<app-root>Loading...</app-root>標籤,這個標籤用來展現該組件的內容 *templateUrl 組件的模板,定義了組件的佈局和內容 *styleUrls 該模板引用那個css樣式 * */ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.css'] }) /*AppComponent原本就是一個普通的typescript類,可是上面的組件元數據裝飾器告訴Angular,AppComponent是一個組件,須要把一些元數據附加到這個類上,Angular就會把AppComponent當組件來處理*/ export class AppComponent { /*這個類實際上就是該組件的控制器,咱們的業務邏輯就是在這個類中編寫*/ title = '學習Angular'; } 

組件相關的概念

  1. 組件元數據裝飾器(@Component
    簡稱組件裝飾器,用來告知Angular框架如何處理一個TypeScript類.
    Component裝飾器包含多個屬性,這些屬性的值叫作元數據,Angular會根據這些元數據的值來渲染組件並執行組件的邏輯
  2. 模板(Template
    咱們能夠經過組件自帶的模板來定義組件的外觀,模板以html的形式存在,告訴Angular如何來渲染組件,通常來講,模板看起來很像html,可是咱們能夠在模板中使用Angular的數據綁定語法,來呈現控制器中的數據。
  3. 控制器(controller
    控制器就是一個普通的typescript類,他會被@Component來裝飾,控制器會包含組件全部的屬性和方法,絕大多數的業務邏輯都是寫在控制器裏的。控制器經過數據綁定與模板來通信,模板展示控制器的數據,控制器處理模板上發生的事件。

裝飾器,模板和控制器是組件的必備要素。還有一些可選的元素,好比:

  • 輸入屬性(@inputs):是用來接收外部傳入的數據的,Angular的程序結構就是一個組件樹,輸入屬性容許在組件樹種傳遞數據
    提供器(providers):這個是用來作依賴注入的
  • 生命週期鉤子(LifeCycle Hooks):一個組件從建立到銷燬的過程當中會有多個鉤子會被觸發,相似於Android中的Activity的生命週期
  • 樣式表:組件能夠關聯一些樣式表
  • 動畫(Animations): Angular提供了一個動畫包來幫助咱們方便的建立一些跟組件相關的動畫效果,好比淡入淡出等
  • 輸出屬性(@Outputs):用來定義一些其餘組件可能須要的事件或者用來在組件之間共享數據

組件的中關係就以下圖所示

 
image.png

下面咱們來看看模塊文件

  • app.module.ts:這個文件表示模塊
  • AppComponent相似,模塊也須要裝飾器來裝飾
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { HeroesComponent } from './heroes/heroes.component'; @NgModule({ declarations: [ // 聲明模塊裏有什麼東西 只能聲明:組件/指令/管道 AppComponent, HeroesComponent ], // 聲明該模塊所依賴的模塊 imports: [ BrowserModule, AppRoutingModule ], // 默認狀況下是空的 providers: [], // 聲明模塊的主組件是什麼 bootstrap: [AppComponent] }) export class AppModule { } 

2.4 Angular cli

https://cli.angular.io

經過ng g列出當前命令

 
ng g

1. 建立新組件 ng generate component component-name

ng g component components/header 指定生成到哪一個目錄

該命令會把生成的組件,添加到 src/app/app.module.ts 文件中 @NgModuledeclarations 列表中聲明

 
image.png

2. 使用 Angular CLI 建立一個名叫 hero 的服務

ng generate service hero

該命令會在 src/app/hero.service.ts 中生成 HeroService 類的骨架。 HeroService 類的代碼以下:

import { Injectable } from '@angular/core'; @Injectable({ providedIn: 'root', }) export class HeroService { constructor() { } } 

3. 添加 AppRoutingModule

ng generate module app-routing --flat --module=app 
  • --flat 把這個文件放進了 src/app 中,而不是單獨的目錄中。
  • --module=app 告訴 CLI 把它註冊到 AppModuleimports 數組中。

生成的文件是這樣的:

src/app/app-routing.module.ts (generated)
content_copy
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; @NgModule({ imports: [ CommonModule ], declarations: [] }) export class AppRoutingModule { } 

修改後

import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; const routes: Routes = []; @NgModule({ imports: [RouterModule.forRoot(routes)], exports: [RouterModule] }) export class AppRoutingModule { } 

3、angular組件及組件裏的模板

3.1 建立angualr組件

1. 建立組件

ng g component components/header

2. 使用組件

<app-header></app-header> 

3.2 Angular 綁定數據

1. 數據文本綁定

定義數據幾種方式

 
定義數據幾種方式
<h1>{{title}}</h1> 

2. 綁定HTML

this.h="<h2>這是一個 h2 用[innerHTML]來解析</h2>" 
<div [innerHTML]="h"></div> 

3.3 聲明屬性的幾種方式

  • public 共有(默認) 能夠在類裏外使用
  • protected 保護類型 只能在當前類和子類中使用
  • private 私有類型 只能在當期類使用

3.4 綁定屬性

[]包裹

<div [id]="id" [title]="msg">調試工具看看個人屬性</div> 
 
image.png

3.5 數據循環 *ngFor

*1. ngFor 普通循環

export class HomeComponent implements OnInit { arr = [{ name: 'poetries', age: 22 }, { name: 'jing' , age: 31}]; constructor() { } ngOnInit() { } } 
<ul *ngIf="arr.length>0"> <li *ngFor="let item of arr">{{item.name}}- {{item.age}}</li> </ul> 

2. 循環的時候設置 key

<ul> <li *ngFor="let item of list;let i = index;"> <!-- 把索引index賦給i --> {{item}} --{{i}} </li> </ul> 

3. template 循環數據

<ul> <li template="ngFor let item of list"> {{item}} </li> </ul> 

3.6 條件判斷 *ngIf

<p *ngIf="list.length > 3">這是 ngIF 判斷是否顯示</p> <p template="ngIf list.length > 3">這是 ngIF 判斷是否顯示</p> 

3.7 *ngSwitch

<ul [ngSwitch]="score"> <li *ngSwitchCase="1">已支付</li> <li *ngSwitchCase="2">訂單已經確認</li> <li *ngSwitchCase="3">已發貨</li> <li *ngSwitchDefault>無效</li> </ul> 

3.8 執行事件 (click)=」getData()」

<button class="button" (click)="getData()"> 點擊按鈕觸發事件 </button> <button class="button" (click)="setData()"> 點擊按鈕設置數據 </button> 
getData(){ /*自定義方法獲取數據*/ //獲取 alert(this.msg); } setData(){ //設置值 this.msg='這是設置的值'; } 

3.9 表單事件

<input
type="text" (keyup)="keyUpFn($event)"/> <input type="text" (keyup)="keyUpFn($event)"/> 
keyUpFn(e){
    console.log(e) } 

3.10 雙向數據綁定

<input [(ngModel)]="inputVal"> 

注意引入:FormsModule

import {FormsModule} from '@angular/forms' NgModule({ declarations: [ AppComponent, HeaderComponent, FooterComponent, NewsComponent ], imports: [ BrowserModule, FormsModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { } 
<!--使用--> <input type="text" [(ngModel)]="inputValue"/> {{inputValue}} 

3. 11 [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]:

<div [ngStyle]="{'background-color':'green'}">你好 ngStyle</div> 
public attr='red'; 
<div [ngStyle]="{'background-color':attr}">你好 ngStyle</div> 

3.12 管道

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

其餘管道

angular中的管道(pipe)是用來對輸入的數據進行處理,如大小寫轉換、數值和日期格式化等

angular中的管道(pipe) 以及自定義管道適用於angular4 angualr5 angualr6 angular7

經常使用的管道(pipe)有

1. 大小寫轉換

<!--轉換成大寫--> <p>{{str | uppercase}}</p> <!--轉換成小寫--> <p>{{str | lowercase}}</p> 

2. 日期格式轉換

<p> {{today | date:'yyyy-MM-dd HH:mm:ss' }} </p> 

3. 小數位數

接收的參數格式爲{最少整數位數}.{最少小數位數}-{最多小數位數}

<!--保留2~4位小數--> <p>{{p | number:'1.2-4'}}</p> 

4. JavaScript 對象序列化

<p> {{ { name: 'semlinker' } | json }} </p> <!-- Output: { "name": "semlinker" } --> 

5. slice

<p>{{ 'semlinker' | slice:0:3 }}</p> <!-- Output: sem --> 

6. 管道鏈

<p> {{ 'semlinker' | slice:0:3 | uppercase }} </p> <!-- Output: SEM --> 

7. 自定義管道

自定義管道的步驟:

  • 使用 @Pipe 裝飾器定義 Pipemetadata 信息,如 Pipe 的名稱 - 即 name 屬性
  • 實現 PipeTransform 接口中定義的 transform 方法

7.1 WelcomePipe 定義

import { Pipe, PipeTransform } from '@angular/core'; [@Pipe](/user/Pipe)({ name: 'welcome' }) export class WelcomePipe implements PipeTransform { transform(value: string): string { if(!value) return value; if(typeof value !== 'string') { throw new Error('Invalid pipe argument for WelcomePipe'); } return "Welcome to " + value; } } 

7.2 WelcomePipe 使用

<div> <p ngNonBindable>{{ 'semlinker' | welcome }}</p> <p>{{ 'semlinker' | welcome }}</p> <!-- Output: Welcome to semlinker --> </div> 

7.3 RepeatPipe 定義

import {Pipe, PipeTransform} from '@angular/core'; [@Pipe](/user/Pipe)({name: 'repeat'}) export class RepeatPipe implements PipeTransform { transform(value: any, times: number) { return value.repeat(times); } } 

7.4 RepeatPipe 使用

<div> <p ngNonBindable> {{ 'lo' | repeat:3 }} </p> <p> {{ 'lo' | repeat:3 }} </p> <!-- Output: lololo --> </div> 

3.13 實現一我的員登記表單-案例

 
image.png
# 建立組件 ng g component components/form 
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-form', templateUrl: './form.component.html', styleUrls: ['./form.component.scss'] }) export class FormComponent implements OnInit { public peopleInfo:any = { username: '', sex: '2', cityList: ['北京', '上海', '深圳'], city: '上海', hobby:[{ title: '吃飯', checked:false },{ title:'睡覺', checked:false },{ title:'敲代碼', checked:true }], mark:'' } constructor() { } ngOnInit() { } doSubmit(){ /* jquery dom操做 <input type="text" id="username" /> let usernameDom:any=document.getElementById('username'); console.log(usernameDom.value); */ console.log(this.peopleInfo); } } 
<h2>人員登記系統</h2> <div class="people_list"> <ul> <li>姓 名:<input type="text" id="username" [(ngModel)]="peopleInfo.username" value="fonm_input" /></li> <li>性 別: <input type="radio" value="1" name="sex" id="sex1" [(ngModel)]="peopleInfo.sex"> <label for="sex1">男 </label>    <input type="radio" value="2" name="sex" id="sex2" [(ngModel)]="peopleInfo.sex"> <label for="sex2">女 </label> </li> <li> 城 市: <select name="city" id="city" [(ngModel)]="peopleInfo.city"> <option [value]="item" *ngFor="let item of peopleInfo.cityList">{{item}}</option> </select> </li> <li> 愛 好: <span *ngFor="let item of peopleInfo.hobby;let key=index;"> <input type="checkbox" [id]="'check'+key" [(ngModel)]="item.checked"/> <label [for]="'check'+key"> {{item.title}}</label> &nbsp;&nbsp; </span> </li> <li> 備 注: <textarea name="mark" id="mark" cols="30" rows="10" [(ngModel)]="peopleInfo.mark"></textarea> </li> </ul> <button (click)="doSubmit()" class="submit">獲取表單的內容</button> <br> <br> <br> <br> <pre> {{peopleInfo | json}} </pre> </div> 
h2{ text-align: center; } .people_list{ width: 400px; margin: 40px auto; padding:20px; border:1px solid #eee; li{ height: 50px; line-height: 50px; .fonm_input{ width: 300px; height: 28px; } } .submit{ width: 100px; height: 30px; float: right; margin-right: 50px; margin-top:120px; } } 

3.14 實現一個完整的ToDo-案例

 
image.png

基礎版

# 建立組件 ng g component components/todo 
<h2>todoList</h2> <div class="todolist"> <input class="form_input" type="text" [(ngModel)]="keyword" (keyup)="doAdd($event)" /> <hr> <h3>待辦事項</h3> <ul> <li *ngFor="let item of todolist;let key=index;" [hidden]="item.status==1"> <input type="checkbox" [(ngModel)]="item.status" /> {{item.title}} ------ <button (click)="deleteData(key)">X</button> </li> </ul> <h3>已完成事項</h3> <ul> <li *ngFor="let item of todolist;let key=index;" [hidden]="item.status==0"> <input type="checkbox" [(ngModel)]="item.status" /> {{item.title}} ------ <button (click)="deleteData(key)">X</button> </li> </ul> </div> 
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-todo', templateUrl: './todo.component.html', styleUrls: ['./todo.component.scss'] }) export class TodoComponent implements OnInit { public keyword: string; public todolist: any[] = []; constructor() { } ngOnInit() { } doAdd(e){ if(e.keyCode == 13){ if(!this.todolistHasKeyword(this.todolist, this.keyword)){ this.todolist.push({ title: this.keyword, status: 0 //0表示代辦事項 1表示已完成事項 }); this.keyword=''; }else{ alert('數據已經存在'); this.keyword=''; } } } deleteData(key){ this.todolist.splice(key,1); } //若是數組裏面有keyword返回true 不然返回false todolistHasKeyword(todolist:any, keyword:any){ //異步 會存在問題 // todolist.forEach(value => { // if(value.title==keyword){ // return true; // } // }); if(!keyword) return false; for(var i=0; i<todolist.length; i++){ if(todolist[i].title==keyword){ return true; } } return false; } } 
h2{ text-align: center; } .todolist{ width: 400px; margin: 20px auto; .form_input{ margin-bottom: 20px; width: 300px; height: 32px; } li{ line-height: 60px; } } 

3.15 搜索緩存數據-案例

基礎版

# 建立組件 ng g component components/search 
<div class="search"> <input type="text" [(ngModel)]="keyword" /> <button (click)="doSearch()">搜索</button> <hr> <ul> <li *ngFor="let item of historyList;let key=index;">{{item}} ------ <button (click)="deleteHistroy(key)">X</button></li> </ul> </div> 
import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-search', templateUrl: './search.component.html', styleUrls: ['./search.component.scss'] }) export class SearchComponent implements OnInit { public keyword: string; public historyList: any[] = []; constructor() { } ngOnInit() { } doSearch(){ if(this.historyList.indexOf(this.keyword)==-1){ this.historyList.push(this.keyword); } this.keyword = ''; } deleteHistroy(key){ alert(key); this.historyList.splice(key,1); } } 
.search{ width: 400px; margin: 20px auto; input{ margin-bottom: 20px; width: 300px; height: 32px; } button{ height: 32px; width: 80px; } } 

4、Angular 中的服務

4.1 服務

定義公共的方法,使得方法在組件之間共享調用

 
image.png

1. 建立服務命令

ng g service my-new-service

# 建立到指定目錄下面 ng g service services/storage 

2. app.module.ts 裏面引入建立的服務

// app.module.ts 裏面引入建立的服務 import { StorageService } from './services/storage.service'; 
// NgModule 裏面的 providers 裏面依賴注入服務 NgModule({ declarations: [ AppComponent, HeaderComponent, FooterComponent, NewsComponent, TodolistComponent ], imports: [ BrowserModule, FormsModule ], providers: [StorageService], bootstrap: [AppComponent] }) export class AppModule { } 

3. 使用的頁面引入服務,註冊服務

import { StorageService } from '../../services/storage.service'; 
constructor(private storage: StorageService) { } 
// 使用 addData(){ // alert(this.username); this.list.push(this.username); this.storage.set('todolist',this.list); } removerData(key){ console.log(key); this.list.splice(key,1); this.storage.set('todolist',this.list); } 

4.2 改造上面的Todo、searchList

searchList

import { Component, OnInit } from '@angular/core'; // 引入服務 import { StorageService } from '../../services/storage.service'; @Component({ selector: 'app-search', templateUrl: './search.component.html', styleUrls: ['./search.component.scss'] }) export class SearchComponent implements OnInit { public keyword: string; public historyList: any[] = []; constructor(public storage: StorageService) { console.log(this.storage.get()); } ngOnInit() { // 修改的地方 var searchlist:any=this.storage.get('searchlist'); if(searchlist){ this.historyList=searchlist; } } doSearch(){ if(this.historyList.indexOf(this.keyword)==-1){ this.historyList.push(this.keyword); // 修改的地方 this.storage.set('searchlist',this.historyList); } this.keyword = ''; } deleteHistroy(key){ alert(key); this.historyList.splice(key,1); } } 

TODOLIST

ngOnInit() {
  // 修改的地方 var todolist:any=this.storage.get('todolist'); if(todolist){ this.todolist=todolist; } } doAdd(e){ if(e.keyCode==13){ if(!this.todolistHasKeyword(this.todolist,this.keyword)){ this.todolist.push({ title:this.keyword, status:0 //0表示代辦事項 1表示已完成事項 }); this.keyword=''; // 修改的地方 this.storage.set('todolist',this.todolist); //用到this必定要注意this指向 }else{ alert('數據已經存在'); this.keyword=''; } } } // 修改的地方 checkboxChange(){ console.log('事件觸發了'); this.storage.set('todolist',this.todolist); } 
<h2>todoList</h2> <div class="todolist"> <input class="form_input" type="text" [(ngModel)]="keyword" (keyup)="doAdd($event)" /> <hr> <h3>待辦事項</h3> <ul> <li *ngFor="let item of todolist;let key=index;" [hidden]="item.status==1"> <!-- add checkboxChange--> <input type="checkbox" [(ngModel)]="item.status" (change)="checkboxChange()"/> {{item.title}} ------ <button (click)="deleteData(key)">X</button> </li> </ul> <h3>已完成事項</h3> <ul> <li *ngFor="let item of todolist;let key=index;" [hidden]="item.status==0"> <!-- add checkboxChange--> <input type="checkbox" [(ngModel)]="item.status" (change)="checkboxChange()" /> {{item.title}} ------ <button (click)="deleteData(key)">X</button> </li> </ul> </div> 

5、Dom 操做以及@ViewChild、 執行 css3 動畫

1. Angular 中的 dom 操做(原生 js)

ngAfterViewInit(){
var boxDom:any=document.getElementById('box'); boxDom.style.color='red'; } 

2. Angular 中的 dom 操做(ViewChild)

import { Component ,ViewChild,ElementRef} from '@angular/core'; 
@ViewChild('myattr') myattr: ElementRef; 
<div #myattr></div> 
ngAfterViewInit(){
let attrEl = this.myattr.nativeElement; } 
 
@viewChild

3. 父子組件中經過 ViewChild 調用子組件 的方法

調用子組件給子組件定義一個名稱

<app-footer #footerChild></app-footer> 

引入 ViewChild

import { Component, OnInit ,ViewChild} from '@angular/core'; 

ViewChild 和剛纔的子組件關聯起來

@ViewChild('footerChild') footer 

在父組件中調用子組件方法

run(){ 
    this.footer.footerRun(); } 

6、Angular 父子組件以及組件之間通信

 
父子組件通信

6.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. 子組件中使用父組件的數據

<p> child works! {{msg}} </p> 

5. 把整個父組件傳給子組件

經過this傳遞整個組件實例

<app-header [home]="this"></app-header> 
export class HeaderComponent implements OnInit { @Input() home:any constructor() { } ngOnInit() { } } 

執行父組件方法 this.home.xxx()

6.2 子組件經過@Output 觸發父組件的方法(瞭解)

1. 子組件引入 Output 和 EventEmitter

import { Component, OnInit ,Input,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

<!--$event就是子組件emit傳遞的數據--> <app-header (outer)="runParent($event)"></app-header> 

5. 父組件接收到數據會調用本身的 runParent 方法,這個時候就能拿到子組件的數據

//接收子組件傳遞過來的數據 runParent(msg:string){ alert(msg); } 

6.3 父組件經過@ViewChild 主動獲取子組 件的數據和方法

1. 調用子組件給子組件定義一個名稱

<app-footer #footerChild></app-footer> 

2. 引入 ViewChild

import { Component, OnInit ,ViewChild} from '@angular/core'; 

3. ViewChild 和剛纔的子組件關聯起來

@ViewChild('footerChild') footer; 

4. 調用子組件

run(){ this.footer.footerRun(); } 

6.4 非父子組件通信

  • 公共的服務
  • Localstorage (推薦)
  • Cookie

7、Angular 中的生命週期函數

7.1 Angular中的生命週期函數

官方文檔:https://www.angular.cn/guide/lifecycle-hooks

  • 生命週期函數通俗的講就是組件建立、組件更新、組件銷燬的時候會觸發的一系列的方法。
  • Angular 使用構造函數新建一個組件或指令後,就會按下面的順序在特定時刻調用這些 生命週期鉤子方法。
  • 每一個接口都有惟一的一個鉤子方法,它們的名字是由接口名再加上ng前綴構成的,好比OnInit接口的鉤子方法叫作ngOnInit.

1. 生命週期鉤子分類

基於指令與組件的區別來分類

指令與組件共有的鉤子

  • ngOnChanges
  • ngOnInit
  • ngDoCheck
  • ngOnDestroy

組件特有的鉤子

  • ngAfterContentInit
  • ngAfterContentChecked
  • ngAfterViewInit
  • ngAfterViewChecked
 
生命週期鉤子

2. 生命週期鉤子的做用及調用順序

一、ngOnChanges - 當數據綁定輸入屬性的值發生變化時調用
二、ngOnInit - 在第一次 ngOnChanges 後調用
三、ngDoCheck - 自定義的方法,用於檢測和處理值的改變
四、ngAfterContentInit - 在組件內容初始化以後調用
五、ngAfterContentChecked - 組件每次檢查內容時調用
六、ngAfterViewInit - 組件相應的視圖初始化以後調用
七、ngAfterViewChecked - 組件每次檢查視圖時調用
八、ngOnDestroy - 指令銷燬前調用

3. 首次加載生命週期順序

export class LifecircleComponent { constructor() { console.log('00構造函數執行了---除了使用簡單的值對局部變量進行初始化以外,什麼都不該該作') } ngOnChanges() { console.log('01ngOnChages執行了---當被綁定的輸入屬性的值發生變化時調用(父子組件傳值的時候會觸發)'); } ngOnInit() { console.log('02ngOnInit執行了--- 請求數據通常放在這個裏面'); } ngDoCheck() { console.log('03ngDoCheck執行了---檢測,並在發生 Angular 沒法或不肯意本身檢測的變化時做出反應'); } 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 = "數據改變了"; } } 
 
生命週期調用順序

check的能夠對數據作響應操做

<button (click)="changeMsg()">數據改變了</button> <input type='text' [(ngModel)]="userInfo" /> 

點擊按鈕/雙向數據綁定此時觸發瞭如下生命週期。只要數據改變

 
cheked

能夠在check作一些操做

ngDoCheck() {
        //寫一些自定義的操做 console.log('03ngDoCheck執行了---檢測,並在發生 Angular 沒法或不肯意本身檢測的變化時做出反應'); if(this.userinfo!==this.oldUserinfo){ console.log(`你從${this.oldUserinfo}改爲${this.userinfo}`); this.oldUserinfo = this.userinfo; }else{ console.log("數據沒有變化"); } } 

7.2 生命週期鉤子詳解

7.2.1 constructor-掌握

constructor,來初始化類。Angular中的組件就是基於class類實現的,在Angular中,constructor用於注入依賴。組件的構造函數會在全部的生命週期鉤子以前被調用,它主要用於依賴注入或執行簡單的數據初始化操做。

import { Component, ElementRef } from '@angular/core'; @Component({ selector: 'my-app', template: ` <h1>Welcome to Angular World</h1> <p>Hello {{name}}</p> `, }) export class AppComponent { name: string = ''; constructor(public elementRef: ElementRef) {//使用構造注入的方式注入依賴對象 // 執行初始化操做 this.name = 'Semlinker'; } } 

7.2.2 ngOnChanges()

Angular(從新)設置數據綁定輸入屬性時響應。該 方法接受當前和上一屬性值的 SimpleChanges 對象 當被綁定的輸入屬性的值發生變化時調用,首次調用一 定會發生在 ngOnInit()以前。

<!-- 父組件中 傳遞title屬性給header子組件 --> <app-header [title]="title"></app-header> 

此時改變title會觸發ngOnChanges生命週期,而且也會觸發

 
cheked

7.2.3 ngOnInit()--掌握

Angular 第一次顯示數據綁定和設置指令/組件的輸入屬性以後,初始化指令/組件。在第一輪 ngOnChanges() 完成以後調用,只調用一次。能夠請求數據

  • 使用 ngOnInit() 有兩個緣由:
    • 在構造函數以後立刻執行復雜的初始化邏輯
    • Angular 設置完輸入屬性以後,對該組件進行準備。有經驗的開發者會認同組件的構建應該很便宜和安全
import { Component, Input, OnInit } from '@angular/core'; @Component({ selector: 'exe-child', template: ` <p>父組件的名稱:{{pname}} </p> ` }) export class ChildComponent implements OnInit { @Input() pname: string; // 父組件的名稱 constructor() { console.log('ChildComponent constructor', this.pname); // Output:undefined } ngOnInit() { console.log('ChildComponent ngOnInit', this.pname); // output: 輸入的pname值 } } 

7.2.4 ngDoCheck()

檢測,並在發生 Angular 沒法或不肯意本身檢測的變 化時做出反應。在每一個 Angular 變動檢測週期中調用, ngOnChanges()ngOnInit()以後。

7.2.5 ngAfterContentInit()

當把內容投影進組件以後調用。第一次 ngDoCheck() 以後調用,只調用一次

7.2.6 ngAfterContentChecked()

每次完成被投影組件內容的變動檢測以後調用。 ngAfterContentInit() 和每次 ngDoCheck() 以後調

7.2.7 ngAfterViewInit()--掌握

初始化完組件視圖及其子視圖以後調用。第一 次 ngAfterContentChecked() 以後調用,只調用一次。在這裏能夠操做DOM

7.2.8 ngAfterViewChecked()

每次作完組件視圖和子視圖的變動檢測以後調用。 ngAfterViewInit()和每次 ngAfterContentChecked() 以後 調用。

7.2.9 ngOnDestroy()--掌握

Angular 每次銷燬指令/組件以前調用並清掃。在這兒反訂閱可觀察對象和分離事件處理器,以防內存泄 漏。在 Angular 銷燬指令/組件以前調用。好比:移除事件監聽、清除定時器、退訂 Observable 等。

@Directive({
    selector: '[destroyDirective]' }) export class OnDestroyDirective implements OnDestroy { sayHello: number; constructor() { this.sayHiya = window.setInterval(() => console.log('hello'), 1000); } ngOnDestroy() { window.clearInterval(this.sayHiya); } } 

8、Rxjs 異步數據流編程

8.1 Rxjs介紹

RxJSReactiveX 編程理念的 JavaScript 版本。ReactiveX 來自微軟,它是一種針對異步數據 流的編程。簡單來講,它將一切數據,包括 HTTP 請求,DOM 事件或者普通數據等包裝成流的形式,而後用強大豐富的操做符對流進行處理,使你能以同步編程的方式處理異步數據,並組合不一樣的操做符來輕鬆優雅的實現你所須要的功能。

  • RxJS 是一種針對異步數據流編程工具,或者叫響應式擴展編程;可無論如何解釋 RxJS 其目 標就是異步編程,Angular 引入 RxJS 爲了就是讓異步可控、更簡單。
  • RxJS 裏面提供了不少模塊。這裏咱們主要給你們講 RxJS 裏面最經常使用的Observable 和 fromEvent

目前常見的異步編程的幾種方法:

  • 回調函數
  • 事件監聽/發佈訂閱
  • Promise
  • Rxjs

8.2 Promise和RxJS處理異步對比

新建一個services

ng g service services/rxjs

services/rxjs.service.ts中寫如下方法

import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class RxjsService { constructor() { } // Promise 處理異步 getPromiseData() { return new Promise(resolve = >{ setTimeout(() = >{ resolve('---promise timeout---'); }, 2000); }); // RxJS 處理異步: getRxjsData() { return new Observable(observer = >{ setTimeout(() = >{ observer.next('observable timeout'); }, 2000); }); } } 
// 在其餘組件使用服務 import { Component, OnInit } from '@angular/core'; import { RxjsService } from '../../services/rxjs.service'; @Component({ selector: 'app-rxjs', templateUrl: './rxjs.component.html', styleUrls: ['./rxjs.component.scss'] }) export class RxjsComponent implements OnInit { // 注入服務 constructor(public request: RxjsService) { } ngOnInit() { // 調用方法 this.request.getRxjsData().subscribe(data=>{ console.log(data) }) } } 
  • 從上面列子能夠看到 RxJSPromise的基本用法很是相似,除了一些關鍵詞不一樣。Promise 裏面用的是 then()resolve(),而 RxJS裏面用的是 next()subscribe()
  • Rxjs相比Promise要強大不少。 好比 Rxjs 中能夠中途撤回、Rxjs 能夠發射多個值、Rxjs 提供了多種工具函數等等

8.3 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); 

8.4 Rxjs 訂閱後屢次執行

  • 若是咱們想讓異步裏面的方法屢次執行,好比下面代碼。

這一點 Promise是作不到的,對於 Promise來講,最終結果要麼 resole(兌現)、要麼 reject (拒絕),並且都只能觸發一次。若是在同一個 Promise 對象上屢次調用 resolve 方法, 則會拋異常。而 Observable不同,它能夠不斷地觸發下一個值,就像 next()這個方法的 名字所暗示的那樣。

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)); 

8.5 Angualr6.x以前使用Rxjs的工具函數 map filter

注意:Angular6 之後使用之前的rxjs 方法,必須安裝 rxjs-compat 模塊纔可使用 mapfilter 方法。

angular6 後官方使用的是 RXJS6的新特性,因此官方給出了一個能夠暫時延緩咱們不須要修 改 rsjx 代碼的辦法

npm install rxjs-compat
import {Observable} from 'rxjs'; import 'rxjs/Rx'; 
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)); 

8.6 Angualr6.x 之後 Rxjs6.x 的變化以及 使用

8.6.1 Rxjs 的變化參考

Angular5升級到Angular6angular6相比較於angular5整體變化不大,可是在RXJS上面卻有一些變更,下面給你們講講關於Angular6版本升級和RXJS6新特性的講解

1. angular6 Angular7中使用之前的rxjs

對於寫了半年多的項目,模塊已經不少了,因此不可能在升級到angular6後立刻更新全部代碼關於RXJS6的新特性,因此官方給出了一個能夠暫時延緩咱們不須要修改rsjx代碼的辦法。

npm install --save rxjs-compat
  • 優勢: 暫時不用改代碼,能夠一點點地改,直到改完後吧這個包卸掉
  • 缺點: 對於rxjs6renameoperator無效,因此,若是有用到renameAPI,必須手動修改

2. Angular6 之後 RXJS6的變化

RXJS6改變了包的結構,主要變化在 import方式和operator上面以及使用pipe()

2.1 Imports 方式改變

 
image.png

rxjs中相似像導入observable subject 等的再也不進一步導入,而是止於rxjs, rxjs6在包的結構上進行了改變

2.2 operator的改變

 
image.png

總而言之: 相似於建立之類的用的API都是從rxjs引入的,相似於map 之類的操做都是從rxjs/operators引入的

 
image.png

2.3 pipeable observable

 
image.png

2.4 被從新命名的API

 
image.png

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)); 

8.7 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`)); 

9、Angular 中的數據交互(get jsonp post)

9.1 Angular get 請求數據

Angular5.x 之後 getpost 和和服務器交互使用的是 HttpClientModule 模塊。

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://a.itying.com/api/productlist"; this.http.get(api).subscribe(response => { console.log(response); }); 

9.2 Angular post 提交數據

Angular5.x 之後 getpost 和和服務器交互使用的是HttpClientModule 模塊。

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 提交數據

express搭建一個server

// package.json { "dependencies": { "ejs": "^2.5.6", "express": "^4.15.3", "socket.io": "^2.0.3", "body-parser": "~1.17.1" } } 
// app.js 代碼 var express = require('express'); var app=express(); var bodyParser = require('body-parser'); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: false })); /*express容許跨域*/ app.all('*', function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); res.header("X-Powered-By",' 3.2.1') if(req.method=="OPTIONS") res.send(200); else next(); }); //app.use(express.static(path.join(__dirname, 'public'))); app.get('/',function(req,res){ res.send('首頁'); }) app.post('/dologin',function(req,res){ console.log(req.body); res.json({"msg":'post成功'}); }) app.get('/news',function(req,res){ //console.log(req.body); res.jsonp({"msg":'這是新聞數據'}); }) app.listen(3000,'127.0.0.1',function(){ console.log('項目啓動在3000端口') }); 
// angular代碼 doLogin() { // 手動設置請求類型 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); }); } 

9.3 Angular Jsonp 請求數據

1. 在 app.module.ts 中引入 HttpClientModule、HttpClientJsonpModule 並注入

import {HttpClientModule,HttpClientJsonpModule} from '@angular/common/http'; 
imports: [
 BrowserModule,
 HttpClientModule,
 HttpClientJsonpModule
]

3. 在用到的地方引入 HttpClient 並在構造函數聲明

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

3. jsonp 請求數據

// 接口支持jsonp請求 var api = "http://a.itying.com/api/productlist"; this.http.jsonp(api,'callback').subscribe(response => { console.log(response); }); 

9.4 Angular 中使用第三方模塊 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 }); 

10、Angular 中的路由

10.1 Angular 建立一個默認帶路由的項目

1. 命令建立項目

ng new angualrdemo08 --skip-install 

2. 建立須要的組件

ng g component home
ng g component news
ng g component newscontent

3. 找到 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' } ]; 

4. 找到 app.component.html 根組件模板,配置 router-outlet 顯示動態加載的路由

<h1> <a routerLink="/home">首頁</a> <a routerLink="/news">新聞</a> </h1> <router-outlet></router-outlet> 

10.2 routerLink 跳轉頁面 默認路由

<a routerLink="/home">首頁</a> <a routerLink="/news">新聞</a> 
//匹配不到路由的時候加載的組件 或者跳轉的路由 { path: '**', /*任意的路由*/ // component:HomeComponent redirectTo:'home' } 

10.3 routerLinkActive 設置routerLink 默認選中路由

<h1> <a routerLink="/home" routerLinkActive="active">首頁</a> <a routerLink="/news" routerLinkActive="active">新聞</a> </h1> 
<h1> <a [routerLink]="[ '/home' ]" routerLinkActive="active">首頁</a> <a [routerLink]="[ '/news' ]" routerLinkActive="active">新聞</a> </h1> 
.active{ color:red; } 

10.4 routerLink Get傳遞參數

1. 跳轉

<li *ngFor="let item of list;let key=index;"> <!-- <a href="/news-detail?aid=123">{{key}}--{{item}}</a> --> <a [routerLink]="['/news-detail']" [queryParams]="{aid:key}">{{key}}--{{item}}</a> </li> 

2. 接收參數

import { ActivatedRoute } from '@angular/router'; constructor(public route:ActivatedRoute) { } this.route.queryParams.subscribe((data)=>{ console.log(data); }) 

10.5 動態路由

1.配置動態路由

const routes: Routes = [ {path: 'home', component: HomeComponent}, {path: 'news', component: NewsComponent}, {path: 'newscontent/:id', component: NewscontentComponent}, { path: '', redirectTo: '/home', pathMatch: 'full' } ]; 

2. 跳轉傳值

<a [routerLink]="[ '/newscontent/',aid]">跳轉到詳情</a> <a routerLink="/newscontent/{{aid}}">跳轉到詳情</a> 

3. 獲取動態路由的值

import { ActivatedRoute} from '@angular/router'; constructor( private route: ActivatedRoute) { } ngOnInit() { console.log(this.route.params); this.route.params.subscribe(data=>this.id=data.id); } 

10.6 動態路由的 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]); 

10.7 路由 get 傳值 js 跳轉

1. 引入 NavigationExtras

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

2. 定義一個 goNewsContent 方法執行跳轉,用 NavigationExtras 配置傳參。

goNewsContent() {
    let navigationExtras: NavigationExtras = { queryParams: { 'session_id': '123' }, fragment: 'anchor' }; this.router.navigate(['/news'], navigationExtras); } 

3. 獲取 get 傳值

constructor(private route: ActivatedRoute) { console.log(this.route.queryParams); } 

10.8 父子路由

1. 建立組件引入組件

import { NewsaddComponent } from './components/newsadd/newsadd.component'; import { NewslistComponent } from './components/newslist/newslist.component'; 

2. 配置路由

{
    path: 'news', component: NewsComponent, children: [{ path: 'newslist', component: NewslistComponent }, { path: 'newsadd', component: NewsaddComponent }] } 

3. 父組件中定義 router-outlet

<router-outlet></router-outlet> 

11、更多參考