angular4.0

angular4的安裝

  1. 確保node和npm都是最新版的,個人是用nvm來管理node.
    因此用:
nvm install stable #安裝最新版node
nvm install 8.4.0 # 安裝8.4.0版本的node
nvm ls #列出可以使用的node
nvm use 8.4.0 #使用8.4.0版本的node;
  1. 設置淘寶鏡像
npm configset registry https://registry.npm.taobao.org
  1. angular-cli是typescript寫的,須要typescript的環境
npm install -g typescript typings
  1. 安裝angular-cli.angular-cli是angular4專屬的命令工具
npm install -g angular-cli@latest  //若是用bash安裝失敗的話,能夠在桌面使用命令行工具cmd,來安裝
  1. 安裝好後,就多了一個命令ng.能夠用來建立angular4項目
ng new angulardemo
  1. 建立完成,就能夠開啓服務器,運行angular4項目了
npm run start
  1. 若是要下載肯定版本的angular-cli,好比1.0.0.能夠用
npm install -g angular-cli/@1.0.0
  1. angular官網文檔
https://www.angular.cn/

在angular4中引入jquery庫和bootstrap

  1. 在angular-cli.json文件中app下面的styles數組裏面是引入的css文件.scripts數組是引入的js文件.好比要
    引入jquery庫的話,就把jquery對應的地址寫在scripts數組裏,要引入bootstrap庫的話,就把js文件加入到scripts數組中
    css文件加在styles數組中;
  2. 由於angular4是typescript環境,因此jquery和bootstrap要使用的話,須要下載對應的typescript解析器;

jquery: npm install @types/jquery --save-devcss

bootstrap: npm install @types/bootstrap --save-devhtml

路由

子路由

{ path : "home", component: HomeComponent,
    children: [
        {path: "list", component: HomeList},
        {path: "create", component: HomeCreate},
    ]
}

主路由在跳路由時,路徑是直接寫的<a [routerLink]="['/product']">詳情</a>node

若是是子路由在同級之間跳轉,路徑是以./開頭的,好比product下面有create和list,路徑不用寫product/list,而是./list
<a [routerLink]="['./list']">詳情</a>jquery

路由對象

路由的五個對象typescript

  1. routes : 保存路由配置信息,就是angularJs裏面的router文件
  2. RouterOutlet: 在html中標記路由內容呈現位置的佔位符,就是標記路由控制的範圍標記
  3. Router: 跳轉路由連接用的,在controller裏面用
  4. RouterLink: 跳轉路由鏈接用和Router一個做用,區別是在html中的a標籤上使用
  5. ActivatedRoute: 路由跳轉時,從一個路由到另外一個路由跳轉時,保存的路由的參數信息和angularJs的$stateParams相似;

這裏面的路由,配置的是路徑和組件的對應關係,而不是和模塊的對應
path:"user" (path不能以/開頭) 若是path: "**",通配符匹配,必須放在最後面
compoent:"A"npm

<a [routerLink]="['/']">主頁</a>
    <a [routerLink]="['/product']">詳情</a>
    <router-outlet></router-outlet>
    [routerLink] 的[]表示屬性綁定
    <button (click)="handler()"><button>事件綁定

在 app.components.ts文件中的組件類函數中添加json

constructor(private router: Router) {}//導入router對象
handler(){
      this.router.navigate(["/product"])
}   //設置handler函數,路由跳轉

在路由中傳遞數據

  1. 在查詢字符串中傳遞

/product?id=1&name=2 => ActivatedRoute.queryParams[id]bootstrap

<a [routerLink] = "['/product']"  [queryParams]="{id: 1}"></a>

export class ProductComponent implements Oninit {
    private productId: number;
    construct (private routeInfo: ActivatedRoute){}
    ngOnInit(){
        this.productId = this.routeInfo.snapshot.queryParams["id"];
    }
}
  1. 在路徑中傳遞數據

{path: /product/:id} => /product/1 => ActivatedRoute.params[id]數組

<a [routerLink] = "['/product', 1]"></a>

this.id = this.routeInfo.params["_value"]["id"];
  1. 在路由配置中傳遞數據
    {path: /product, component: ProductComponent, data:[{isProd: true}]}
    => ActivatedRoute.data[0][isProd]

依賴注入

注入器和提供器

  1. 注入器
//在組件類中的構造函數中,注入服務;
constructor(private productService: ProductService){}
  1. 提供器
//在
providers: [{provide: ProductService, useClass: ProductService}]
// 能夠簡寫成
providers: [ProductService]
//useClass實例化方式,new誰. provide是token,就是在構造函數中聲明的ProductService1;

服務的建立,依賴注入

  1. 建立服務:
ng g service shared/product

在shared文件夾中建立一個product的服務;bash

  1. 聲明提供器
  • 在主模塊中聲明. 在app.modules.ts文件的主模塊裝飾器中.
    全部的組件均可用.最經常使用.
@ngModule({providers:[productService]})
  • 在單個組件中.在組件的裝飾器中.只有該組件及其子組件可用.少用
@Component({providers: [{provide: ProductService, useClass: AnotherProductService}]})
  1. 聲明注入器
export class productComponent implements Oninit{
    product: product; //聲明變量

    //在構造函數中注入服務
    constructor(private productService: productService){}
    ngOnInit(){
        this.product = this.productService.getProduct();
    }
}
  • 在服務中的裝飾器@injectable()表示能夠再注入其餘的服務;

數據綁定

屬性綁定

angular4的屬性綁定
<img [src]="imgUrl">
用[]把src屬性包起來,[src]就是angular4的屬性綁定,能夠直接使用在此組件中定義的imgUrl的值;
css類屬性綁定
<span *ngFor="let star of stars" class="btn" [class.primite] = "star">
[class.promite] = "star"是說span標籤有沒有css類promite,取決於star是否是true。和ng-class相似;
用[]把組件中的數據,綁定到模板上

export class BindComponent implements OnInit{
    name: string;   //值
    constructor(){}
    ngOnInit()
}

<input [value]="name">

//從組件到模板

事件綁定

用()把組件中的事件綁定到組件中的方法中

<input (input)="doOnInput($event)">

export class BindComponent implements OnInit{
    constructor(){}
    ngOnInit()
    doOnInput(event) {}
}
 //單項綁定,從模板到控制器

雙向綁定

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

export class BindComponent implements OnInit{
    name: string;
    constructor(){}
    ngOnInit()
    doOnInput(event) {}
}

在標籤中用[(ngModel)],在組件類中直接定義:name: string;不在contructor中,也不在哪一個鉤子中;

表單驗證

模板式表單

在裝飾器中導入FormsModule

@NgModule({
    imports: [
        FormsModule,
        HttpModule,
        ...
    ]
})

模板式表單只能用指令來定義數據模型,如下三個指令都來自FormsModule

  1. NgForm : 表明整個表單,自動的添加到form標籤上。跟angular1同樣;
    能夠加在div上
    與form標籤功能相同.
    若是不想要angular接管form標籤能夠加一個ngNoForm.
  2. NgModel : 雙向數據綁定,標記一個標籤成爲數據模型的一部分
  3. NgModelGroup

在表單用使用ngModel

<input type="checkbox" ngModel #isHost="ngModel" name="isHost"> {{isHost.value}}
 <div class="form-group" *ngIf="isHost.value"> </div>

在input標籤中添加ngModel和name屬性,把該標籤的數據添加到表單數據模型中
用#isHost="ngModel" 把標籤的值暴露給頁面模板,若是沒有這個屬性就沒辦法在html頁面上用{{isHost}}顯示出來;

響應式表單,

在裝飾器中導入ReactiveFormsModule

@NgModule({
    imports: [
        ReactiveFormsModule,
        HttpModule,
        ...
    ]
})

建立響應式表單須要兩步

  1. 建立一個數據模型
  2. 在模板上連接這個數據模型;

建立數據模型

數據模型由FormControl, FormGroup,FormArray這三個類型組成;

  1. FromControl,對應指令FormGroup,FromGroupName
    表明一個表單元素的值和狀態
export class CdAppPublishComponent implements OnInit {
    username: FormControl = new FormControl("aaa") //新建一個表單元素,初始值爲"aaa"
    formModel: FormGroup = new FormGroup({      //新建一個FormGroup
        form: new FromControl(),
        to: new FromControl(),
    })
    emails: FormArray = new FormArray([
        new FormControl("a@a.com"),
    ])

}
  1. FormGroup,對應的指令 formControl, formControlName
    表明多個表單(FormControl)的集合,或整個表單;
  2. FormArray 對應的指令: formArrayName;
    表明一個能夠增加的表單集合;只能經過序號來訪問;
  3. 使用的指令與模板式表單不一樣
    formGroupName,FormControlName,formArrayName,都是經過表單的name屬性來連接的;
  4. 響應式表單不能用"isHost"="ngModel"的方式在頁面模板上使用,只能在代碼中操做,
    而模板式表單只能再頁面模板上使用不能在代碼中操做;

組件

建立組件

  1. angular4的命令行工具angular-cli,能夠幫助咱們建立組件
ng g component navbar

建立一個navbar導航組件;會在app文件夾中直接建立一個navbar文件夾,裏面是相應的文件;
建立後會自動注入到appModules父組件中

組件間的數據傳遞

把父組件中的數據傳遞給子組件;
<app-stars [rating] = "product.rating">
app-stars這個組件的rating屬性是由父組件的product.rating傳遞來的
在app-stars組件的構造函數的鉤子OnInit中設置
@Input
private rating: number = 0;
rating變量是number類型,初始化值是0,私有數據,
由父組件傳入(@Input輸入裝飾器);
也就是說裝飾器是直接寫在一個變量,構造函數的上面起做用的

組件的輸入屬性

輸入屬性是指被input裝飾器註解的屬性;用來從父組件接受數據.屬性綁定是單向的,從父組件到子組件

在子組件中

//
import { Component,ngOnInit, Input } from "@angular/forms";
//引入Input裝飾器,沒錯裝飾器也須要引入;

export class OrderComponent implements OnInit{

    //用輸入裝飾器修飾這兩個變量,表示這兩個值是從父組件傳入的;
    @Input()
    storkCode: string;

    @Input()
    amount: number;

    constructor(){};
    ngOnInit(){}
}
<div>買{{amount}}個 {{storkCode}}</div>

在父組件中

export class AppComponent {
    stock = "";
}
<div>我是父組件</div>
<input type="text" placeholder= "請輸入股票代碼" [(ngModel)]= "stock" >
<app-order [stockCode]="stock" [amount]="100"></app-order>

從父組件到子組件傳遞數據的兩種方式

  1. 屬性綁定
    只有造成了父子組件關係才能在 標籤上傳遞數據,在子組件中數據的是聲明在組件類中做爲自身的一個屬性來獲取的;
    @Input() storkCode: string;
  2. 經過路由
    路由參數是經過構造函數來傳遞的;須要在構造函數中傳入對象ActivatedRoute,
    用這個對象,再經過參數快照或參數訂閱來獲取到數據
constructor(routeInfo: ActivatedRoute) {
}
ngOnInit(){
        this.productId = this.routeInfo.snapshot.queryParams["id"];
}

組件的各個部分的說明

//js運行環境,引入要使用的組件(Component),鉤子(ngOnInit),裝飾器(Input)
import { Component,ngOnInit, Input } from "@angular/forms";
/*
1. export導出,使外部可使用這個對象
2. class表示這是一個對象的類,裏面的屬性(好比title)都是this.title.
裏面的函數好比console(){console.log("123")}都是this.console;
而上面的this(實際上並不存在)指的是用這個組件類實例化出來的組件
3. 在export class OrderComponent implements OnInit{}是一個對象,不是函數。裏面不能直接運行js.
要運行js的話應該在constructor(){console.log("這裏面")}或者是ngOnInit(){}裏面;
*/
export class OrderComponent implements OnInit{
    //這裏面定義的變量,函數,都是能夠爆露在組件實例的模板上的值;constructor是構造函數。
    //ngOnInit是當初始化是運行的函數鉤子;
    //用輸入裝飾器修飾這兩個變量,表示這兩個值是從父組件傳入的;
    @Input()
    storkCode: string;
    @Input()
    amount: number;
    constructor(){};
    ngOnInit(){}
}

組件中的OnChanges函數

組件中的OnChanges函數,能監控自身組件的值的變化,也能監控父組件傳入的值的變化。
要被OnChanges函數監控,要知足下列條件

  1. 首先要在自己組件類函數中定義了變量;
  2. 因爲某種方式發生了改變,或者有父組件傳入,或者是再本組件中有input標籤和雙向數據綁定;
  3. 變量的值類型是簡單數據類型,若是是複雜數據類型,好比對象。那麼對象屬性的改變了,這個變量自己的數據指向並無發生改變。因此不會被OnChanges函數監控到;可是值依然會改變,由於組件還有監控機制;
export class ChildComponent implements OnInit, OnChanges {
    greeting: string;
    user: {name: string};
    constructor(){}
    //changes是ngOnChanges的參數,監控到的變化信息存儲在裏面。SimpleChanges是
    //changes的數據類型;
    ngOnChanges(changes: SimpleChanges): void {
        console.log(changes);
    }
    //changes的數據模型以下所示
    {
        "greeting": {
            "previousValue": {},
            "currentValue": "Hello"
        }
    }
}

angular的變動檢測機制和DoCheck鉤子

  1. 要使用angular的變動檢測須要在package.json的dependecies中添加zone.js
  2. 在angular應用中的任何改變,事件,異步都會觸發變動檢測;
  3. 變動檢測有兩種策略。
    • 一是默認的Default,在組件中的任何地方的變化都會引發整個應用的全部組件的檢測
    • 還有OnPush策略。只有輸入屬性發生改變的時候纔會進行自身和子組件的變動檢測;
  4. 一個例子
ngDoCheck(): void {
    if(this.user.name !== this.oldUser.name) {
        console.log("改變了「)
    }
}
  1. 要注意的是ngDoCheck這個鉤子的使用,要很是的當心,他的代碼要很是的輕量級,
    邏輯須要很是的清晰。由於整個應用的任何一個組件的改變,事件等,都會觸發全部組件的ngDoCheck鉤子
    甚至鼠標在頁面上隨意點幾下都會觸發。很容易形成很是大的性能消耗;
  2. 在全部的鉤子中,只要名字裏有 Check 這個字段。都會有上門面第五條的性能問題
    包括: ngAfterContentChecked, ngAfterViewChecked,ngDoCheck;
  3. 綜上ngDoCheck這個鉤子不適合作三級聯動

組件的鉤子ngAfterViewInit, ngAfterViewChecked

  1. ngAfterViewInit視圖組裝完成以後的初始化,ngAfterViewChecked視圖組裝後的檢測
  2. ngAfterViewInit只會在初始化時調用一次,ngAfterViewChecked會在每次視圖變動以後調用
  3. 這兩個都是在視圖組裝完畢以後調用的;
  4. 若是一個組件有子組件,只有子組件的這兩個鉤子調用完以後,父組件的這兩個鉤子纔會被調用
  5. angular不容許在一次變動流程中,在視圖組裝完畢後再去改變視圖。
    簡單的說就是不能再這兩個鉤子中去改變組件中掛載到視圖中的值,不然會報錯。若是必定要這麼作
    能夠把改變值的行爲放在一個setTimeout裏面;在異步流程中改變;
message: string;
    ngAterViewInit(): void {
        setTimeout(() => {
            this.message = "hello";
        }, 0)
    }

父組件使用子組件提供的方法;

  1. 子組件
export class ChildComponent{
    greeting(name: string) {
        console.log(name)
    }
}
  1. 父組件的模板
<app-child #child1></app-child>
<app-child #child2></app-child>
  1. 父組件的組件類
export class ChildComponent{
    @ViewChild("child1")
    child1: ChildComponent;
    ngOnInit(): void {
        this.child1.greeting("tom")
    }
}

父子組件之間的投影,ng-content

  1. 子組件
<div>
    我是子組件
    <ng-content select=".header"><ng-content>
    <ng-content select=".footer"><ng-content>
</div>
  1. 父組件
<div>
    我是父組件
    <app-child>
        <div class="header">這是頁頭,這個div時父組件投影到子組件中的內容,title: {{title}}</div>
        <div class="footer">這是頁腳,這個div時父組件投影到子組件中的內容</div>
    </app-child>
</div>
<div [innerHTML] = 'divContent'> </div>
export class AppComponent {
    title = "app works";
    divContent = "<div>慕課網;</div>"
}
  1. 在父組件的模板中app-child裏面的內容就會出如今子組件的 標籤的位置
    和angular1的置換指令ng-transclude相似;
  2. 若是子組件中有多個來自父組件的投影,那麼能夠用select="css選擇器"來區分;
  3. 在本組件中,能夠用[innerHTML]屬性來把組件類中的html字符串,現式出來;

組件的鉤子ngOnDestroy

  1. 這個鉤子會在路由變更致使頁面上再也不顯示本組件時調用
  2. 通常用來銷燬setTimeout,setInterval之類的;

組件的生命週期;

  1. constructor,ngOnChanges, ngOnInit, ngDoCheck這四個函數依次執行,用來
    構建組件的屬性。進行屬性初始化
    • constructor實例化對象
    • ngOnChanges初始化輸入屬性;
    • ngOnInit初始化除了輸入屬性之外的其餘全部的屬性;
    • ngDoCheck作一次變動檢查,進行到這裏時組件的全部的屬性都被賦值了;
  2. ngAfterContentInit, ngAfterContentChecked會在投影完成以後調用。是構建dom樹,順序是從父到子。相似angular1的compile階段
    此時還能夠對組件的值進行改變;
  3. ngAfterViewInit,ngAfterViewChecked,是視圖構建完成以後調用。
    相似angular1的link階段;此時就不能對組件的值進行改變了,若是非要改變就在setTimeout裏面改;
  4. 在應用上的任何組件的任何行爲不論是修改值,異步操做,事件,都會致使全部的組件
    的全部帶有Check字段的鉤子的執行;
  5. 若是應用的行爲致使了組件輸入屬性的變化,會引起ngOnChanges的執行;
相關文章
相關標籤/搜索