Angular學習隨筆

最近在看angular4,隨手記的一些angular的隨筆。javascript

新上手或者準備學angular的能夠用做參考,第一次寫博客,筆記不算完整,若老司機發現有不足指出請指出。css

技術交流羣:513590751html

Angular程序架構

組件java

是Angular應用的基本構件塊、能夠把一個組件理解爲一段帶有業務邏輯和數據的html

指令 詳細指令速查web

容許向html添加自定義行爲

模塊typescript

用來將應用中不一樣的部分組成一個Angular框架能夠理解的單元

服務編程

用來封裝可重用的業務邏輯

組件

在組件上聲明模版變量

#varName

組件元數據裝飾器

用來元數據附加到typescript的類上面 從而讓angular把這個類識別爲組件

## selecter:css的選擇器,標誌能夠根據該選擇器做爲html標籤

## templateUrl:指定了html文件做爲組件的模版

## styleUrls:指定了組件模版中的樣式

控制器

控制器是指被@component()裝飾的類

包含與模版相關的全部的屬性與方法

與頁面相關的大部分邏輯都是編寫在控制器裏面

模塊

@NgModule裝飾器

用@NgModule裝飾器生成一個模塊

## 用declarations聲明瞭模塊中有什麼東西(只能聲明組件、指令和管道)

## 用imports聲明瞭模塊依賴的其餘模塊

## 用providers聲明模塊中提供什麼服務(此處只能聲明服務)

## 用bootstrap聲明瞭模塊的主組件

## 在模塊中聲明服務,在全部組件中均可以使用,在組件中聲明服務,只能在組件中使用(每一個想要被注入的服務都須要在服務提供其中聲明)

新建一個Angualr項目

用angular-cli建立一個angular項目

建立:ng new my-app

啓動:ng serve [--open]

    --open:在瀏覽器打開
    
    --routing:生成一個帶route的項目
    
生成組件:ng g component [componentName]
生成服務:ng g service [serviceName]
生成管道:ng g pipe [pipeName]
生成指令:ng g directive [directiveName]

Angular router

名稱 簡介
Routes 路由配置,保存着哪一個URL對應展現哪一個組件,以及在哪一個RouterOutlet中展現組件
Routerlet 在HTML中標記路由內容呈現位置的佔位符指令
Router 負責在運行時執行路由的對象,能夠經過調用其navigate()和navigateByUrl()方法來導航到一個指定的路由
RouterLink 在HTML中聲明路由導航用的指令
ActivatedRoute 當前激活的路由對象,保存着當前路由的信息,如路由地址,路由參數等

路由配置

path:路由URL

component:路由對應的組件

    {path:"**",component:Page404Component}   //404頁面,放到全部路由的最後

children:[{path:"aaa",component:AaaComponent}]子路由

redirectTo:重定向的URL

pathMatch:指定匹配方式,匹配path中的 '',(full徹底匹配,prefix匹配前綴)

loadChildren:延遲加載

canActivate:[class]    //此處調用的類須要在providers裏面聲明,該類實現了CanActivate類 implements CanActivate

canDeactivate:[class]  //此處調用的類須要在providers裏面聲明,該類實現了CanDeactivate類 implements CanDeactivate<component>

resolve:{param1:value1,params2:value2}    //此處調用的類須要在providers裏面聲明,該類實現了Resolve類 implements Resolve<component>

路由時傳遞參數

傳參:

    方式1:/product?id=1&name=2
    
    方式2:{path:/product/:id}  =>  /product/1
    
    方式3:{path:/product,component:ProductComponent,data:[{flag:true}]}

取值:ActivatedRoute.queryParams[id]    //適用於方式1

      ActivatedRoute.params[id]    //適用於方式2
    
      ActivatedRoute.data[0][flag]  //適用於方式3

參數快照

export class ProductComponent implements OnInit {
    
    private name;

    private id;

    constructor(private activatedRoute: ActivatedRoute) {
    }

    ngOnInit() {
        // 訂閱方式 若是會有組件調用自己的狀況就使用訂閱方式
        this.activatedRoute.params.subscribe((params: Params ) => this.id = params["id"] );
        // 快照方式
        this.name = this.activatedRoute.snapshot.queryParams["name"];
        this.id = this.activatedRoute.snapshot.params["id"];
    }
    
}

輔助路由

<router-outlet></router-outlet>
<router-outlet name="aux"></router-outlet>

{path:"xxx",component:XxxComponent,outlet:"aux"}
{path:"yyy",component:YyyComponent,outlet:"aux"}

<a [routerLink]="[{outlets:{aux:null}}]">xxx</a>
<a [routerLink]="[{outlets:{primary:'home',aux:'yyy'}}]">yyy</a>

primary:控制主路由

路由守衛

CanActivate:處理導航到某路由的狀況。

CanDeactivate:處理當前路由離開的狀況。

Resolve:在路由激活以前獲取路由數據。

依賴注入

在providers中註冊接口

在須要引用的類的構造方法的參數中注入

constructor(private params1:Params){}

當使用同一個接口不一樣的實現類時,在providers中聲明providers: [{
    provide: Params,
    useClass: AnotherParams
}]

使用工廠類肯定使用哪一個類時,在providers中聲明providers:[{
    provide: Params,
    useFactory: () => { 
        let depClass = new DepClass(); // 此處工廠方法和DepClass類耦合
        let isLogin = Math.random() > 0.5; // 可能還依賴一個外部的變量來判斷須要建立哪一個類
        //在這裏返回要使用的類型 注意:工廠方法只會在建立第一個須要注入的對象的時候被調用一次 
    }
},DepClass]

// 爲工廠方法解耦合
使用deps屬性來聲明工廠方法依賴的類和變量的provide屬性,在providers中聲明providers:[{
    provide: Params, 
    useFactory: (depClass:DepClass,isLogin) => { 
        //在這裏返回要使用的類型 
    },
    deps: [DepClass,"IS_LOGIN_ENV"]
},DepClass,{
    provide:"IS_LOGIN_ENV",
    useValue:false
}]
useValue的值能夠是基本類型,也能夠是對象類型
angular會吧工廠方法依賴的DepClass類注入到工廠方法

數據綁定

使用插值表達式

<h1>{{productTitle}}</h1>

使用方括號將html標籤的一個屬性綁定到一個表達式上

<img [src]="imgUrl" />
<img src="{{imgUrl}}" />

使用小括號將組件控制器的一個方法綁定爲模版上一個事件的處理器 $event(瀏覽器事件對象)指向觸發事件的dom元素

<button (click)="clickEvent($event)">綁定事件</button>
dom屬性
事件中使用 event.target.value 獲取的值是html元素的dom屬性(dom屬性的值是會發生變化的)
html屬性
使用 event.target.getAttribute("value") 獲取的值是html元素的初始值(html屬性是不會發生變化的)

<div class="aaa bbb" [class]="ccc">這種方式會替換原class屬性的值</div>
<div class="aaa bbb" [class.ccc]="true">這種方式不會替換原class屬性的值</div>
<div [ngClass]="{aaa:isTrue,bbb:isShow}">這種方式能夠控制多個屬性的顯示</div>

雙向數據綁定

<div [(ngModel)]="name">雙向數據綁定</div>

管道

{{name | filter}}
eg:{{birthday | data}}// 將生日轉化成日期格式
eg:{{birthday | data:'yyyy-MM-dd HH:mm:ss'}}// 將生日轉化成指定日期格式

自定義管道

在項目中生成一個管道,而後在管道類的transform方法中對值進行操做。
export class PipeName implements PipeTransform {
        transform(value: any, arg: any): any {
            // value 是要在管道作處理的值
            // arg 是管道後面跟着的參數
        }
    }

響應式編程

一、在項目模塊中引入ReactiveFormsModule模塊

二、在組件中聲明FormControl類型的字段
    eg:formControlName

三、在頁面中控件上聲明[formControl]="formControlName"

四、在組件中訂閱formControlName的valueChanges事件
    eg:this.formControlName.valueChanges.subscribe(value => this.keyword = value);

組件間通信

組件的輸入輸出屬性

輸入屬性
在須要注入的屬性上用@Input註解
在父組件中用[propName]="value"來賦值
輸出屬性
在子組件屬性上用@Output解屬性類型爲EventEmitter<DataType>類型
@Output()
prop:EventEmitter<DataType> = new EventEmitter();
用 prop.emit(dataTypeObj)

在父組件中聲明dataTypeObj:DataType = DataType();//用來存放子組件Output出來的屬性

在父組件引用子組件的標籤上用事件訂閱來訂閱自組建發射的事件
用<child-comp (prop)="propHandler($event);"></child-comp>
// 監控的事件名 prop 和@Output中的參數一致,不傳參時默認和屬性名一致

在父組件中聲明
propHandler(event:DataType){
    // 把子組件Output出來的屬性賦值到父組件的屬性上
    this.dataTypeObj = event;
}

使用中間人模式傳遞數據

兩個子組件,經過@Output數據到父組件和@Input從父組件接收數據來實現組件間通信,父組件爲中間人

組件生命週期以及angular的變化發現機制

組件鉤子:
想要使用這些鉤子,須要先實現對應的接口

被調用一次的鉤子
    
    constructor(組件構造方法,調用該方法時,組件的輸入屬性沒有值)
    
    ngOnInit(初始化組件或指令,調用該方法時,OnChanges方法已被調用,組件的輸入屬性有值)
    
    ngAfterContentInit(和angular的內容投影相關的)
    
    ngAfterViewInit(和angular的視圖初始化和檢查相關的,在此方法不可修改組件的屬性)
    
    ngOnDestroy(組件銷燬,在路由到其餘組件時當前組件被銷燬)
    
被調用屢次的鉤子
    
    ngOnChanges(父組件初始化或修改子組件的輸入屬性的值的時候被調用,若是一個方法沒有輸入屬性,則該方法不會被調用)
    
    ngDoCheck(用來檢測,在每一個angular的變動檢測週期調用)
    
    ngAfterContentChecked(和angular的內容投影相關的)
    
    ngAfterViewChecked(和angular的視圖初始化和檢查相關的,在此方法不可修改組件的屬性)

調用順序:
    
    constructor、ngOnChanges、ngOnInit、ngDoCheck、ngAfterContentInit、ngAfterContentChecked、ngAfterViewInit、ngAfterViewChecked、ngAfterContentChecked、ngAfterViewChecked
父組件調用子組件的方法
#在父組件的模塊中調用子組件的方法

一、在子組件上聲明模版變量 #childName
二、在父組件中聲明一個類型爲 ChildeComponent 的變量 child
三、用 @ViewChild("childName") 註解聲明的變量 child
四、在代碼塊中用 this.child.methodName(args) 來調用子組件的方法

#在父組件的模版中調用子組件的方法

一、在子組件上聲明模版變量 #childName
二、在父組件的模版中綁定事件 (click)="childName.methodName('args')"

父組件內容投影到子組件中

#父組件
<div>
    <child-comp>
        <div class="header">這是頭部</div>
        <div class="footer">這是底部</div>
    </child-comp>
</div>

#子組件
<div>
    <ng-content select=".header"></ng-content>
    <ng-content select=".footer"></ng-content>
</div>

定義單個投影點時能夠不寫class屬性和select屬性

表單處理

模版式表單

表單的數據模型是經過組件模版中的相關指令來定義的,由於使用這種方式定義表單的數據模型時,咱們會受限與HTML的語法,因此,末班驅動方式只是用於一些簡單的場景

可用指令

NgForm

NgModel

NgModelGroup

用#myForm來聲明表單的模版變量,在表單的onSubmit="onSubmit(myForm.value,myForm.valid)"來傳入表單的值和表單是否經過驗證

生成指令

@Directive({
    selecter: "[dirName]", // 在html上做爲屬性使用
    providers: [{provide: NG_VALIDATORS, useValue: mobileValidator, multi: true}] // mobileValidator是已經聲明的驗證器
})

響應式表單

使用響應式表單時,經過編寫TypeScrtipt代碼而不是HTML代碼來建立一個底層的數據模型,在這個模型定義好之後,使用一些特定的指令,將模版上的HTML元素與底層的數據模型鏈接在一塊兒

可用對象

FormControl

userinfo: FormControl = new FormControl("aaa");

FormGroup

FormGroup是多個FormControl的集合

FormArray

使用

方式1、
formModel: FormGroup = new FormGroup({
    username: new FormControl("初始值"),
    password: new FormControl(),
    email: new FormArray([
        "a",
        "b"
    ])
});

方式2、
constructor(fb: FormBuilder){
    this.formModel = fb.group({
        username: ["初始值", Validators.required], // 第二個參數是校驗器,能夠傳一個數組,第三個參數是異步校驗器
        password: [""],
        email: fb.array([
            "a",
            "b"
        ])
    });
}

<!-- 使用 novalidator 阻止瀏覽器默認的表單驗證如:(required) -->
<form [formGroup]="formModel" novalidator>
    <!-- required 驗證表單是否爲空 -->
    <input type="text" ngModel required formControlName="username"/>
    <!-- 第一個參數是校驗器返回的錯誤對象的key,第二個參數是校驗的字段 -->
    <div [hidden]="formModel.hasError('required','username')">用戶名不能爲空</div>
    <input type="text" formControlName="password"/>
    <div *ngFor="let e of email;let i = index;" formArrayName="email">
        <input type="text" [formControlName]="i"/>
    </div>
</form>

表單驗證

校驗器

funcName(control: AbstractControl) {[key: string]: any} {
    return null;
}

eg:

mobileValidator(control: FormControl) any {
    let valid = true;
    return valid ? null : {mobile : true};
}

constructor(fb: FormBuilder){
    this.formModel = fb.group({
        mobile: ["", this.mobileValidator]
    });
}

onSubmit() {
    let isValid:boolean = this.formModel.get("username").valid;  // 獲取字段是否經過驗證
    let error:any = this.formModel.get("username").errors;  //獲取字段未經過驗證的錯誤信息
    this.formModel.valid; // 用來判斷表單是否合法
}

異步校驗器

異步校驗器做爲字段構造的第三個參數傳入
funcName(control: AbstractControl) {[key: string]: any} {
    // 返回的對象用Observable.of方法包裹,delay延遲5s
    return Observable.of({}).delay(5000);
}

eg:

mobileAnsycValidator(control: FormControl) any {
    let valid = true;
    return Observable.of(valid ? null : {mobile : true}).delay(5000);
}

constructor(fb: FormBuilder){
    this.formModel = fb.group({
        mobile: ["", this.mobileValidator, this.mobileAnsycValidator]
    });
}

與服務器通信

引入Http模塊:

一、import Http from "@angular/http";
    
    二、在cunstructor方法中注入:cunstructor(http: Http)
    
    三、使用this.http.get("url",data)獲取數據,而且用.map(res => res.json())把獲取到的數據轉換成json格式
    
    四、用Observable類型的變量接收數據
    
    五、訂閱Observable類型的變量,而且用obs.subscribe(data => this.product = data)來賦值給變量
    
proxy.conf.json配置
    // 意指當前請求是以/api開頭時,把請求轉發到http://loacalhost:8000
    {
        "/api": {
            "target": "http://loacalhost:8000"
        }
    }
    // 在package.json中配置
    ng serve 命令添加參數 --proxy-config proxy.conf.json

使用websocket協議與後臺通訊

service

import {Injectable} from '@angular/core';
import {Observable} from "rxjs/Observable";

@Injectable()
export class WebSocketService {

    ws: WebSocket;

    constructor() {
    }
    
    // 根據傳入的url建立一個websocket協議
    createObservableScoket(url: string): Observable<any> {
        // 建立websocket服務
        this.ws = new WebSocket(url);
        return new Observable(observer => {
            // 返回成功時執行的方法
            this.ws.onmessage = event => observer.next(event.data);
            // 返回錯誤時執行的方法
            this.ws.onerror = event => observer.error(event);
            // 關閉websocket流時執行的方法
            this.ws.onclose = event => observer.complete();
        });
    }

    sendMessage(msg: string) {
        this.ws.send(msg);
    }
}

component

export class SearchComponent implements OnInit {

    constructor(private wsService: WebSocketService) {
    }

    ngOnInit() {
        // 訂閱websocket返回的值
        this.wsService.createObservableScoket("ws://localhost:8085").subscribe(
            data => console.log(data),
            error => console.log(error),
            () => console.log("webSocket已結束!")
        );
    }

}
相關文章
相關標籤/搜索