前言:
本系列在前面兩篇文章,介紹了Zone.js和angular2的基礎概念。而后對於ng2的學習,還是由官方的 Tour of Heroes 開始。
以下內容經過提煉和個人理解,當然也會有不正確的地方,歡迎指正。有興趣的朋友,可以自己開始ng2之旅,再結合本篇文章一起理解。
ng2的配置比較麻煩,任意的引入包可能導致一些報錯,建議直接官方下載 quickStart 。
ng2 將所有api分成7個類型,在查閱api的時候,可以多留意一下他們的類型,便於理解

@Component
@Component 申明一個應用程序可重用的UI組件,可以通過bootstrap實例化,也可以通過它本身directives屬性相互實例化調用。
/* app.component.ts */ import {Component} from '@angular/core'; @Component({ selector: 'app-component', template: `<div>{{title}}</div>` }) export class AppComponent{ title = 'Tour of Heroes'; }
/* main.ts */ import {bootstrap} from '@angular/platform-browser-dynamic' import {AppComponent} from './app.component' bootstrap(AppComponent)
//index.html <body> <app-component></app-component> </body> /* 最終頁面渲染 */ <body> <app-component> <div>Tour of Heroes </div> </app-component> </body>
@Component 會為組件創建一個shadow DOM,將選中的模板加載到shadow DOM,創建所有配置的注入對象。
bootstrap 引導運行@Component時,會先根據@Component 的selector找到dom,並新建一個子注射器,通過一個新Zone實例進行變化檢測,
創建一個shadow DOM並載入到dom節點匯總,實例化組件,最后初始化提供的數據。
shadow dom:
在ng2的文檔里,提及了shadow dom。可以參考文章:Shadow DOM:基礎。
shadow dom能讓dom和css樣式做到有作用域划分,可以相互獨立,樣式不相互影響。
而瀏覽器對shadow dom的支持並不好,但是ng2用其他方式,實現了類似shadow dom的功能。
比如,當@Component配置了styles屬性,在組件實例化的時候,style會被載入到head

如上圖,實際我們的style原本寫的是h1選擇器,ng在后面加上了屬性選擇器[_ngcontent-hvh-1]。
在組件的根dom,ng也會加上[_ngcontent-hvh-1]此屬性。
通過一個屬性選擇器,ng2自動為我們隔離了style的作用域。

每個組件都將會加入一個特定的屬性,屬性后面的數字按照載入順序累加: [_ngcontent-hvh-1] -> [_ngcontent-hvh-2] ......
@Input&@Output:
使用@input綁定標簽屬性,創建組件通信的單向輸入流。需要引入組件:import { Input } from '@angular/core';
“英雄之旅”例子:
/* A */ import { Input } from '@angular/core'; @Component({ selector: 'bank-account', template: ` Bank Name: {{bankName}} Account Id: {{id}} ` }) class BankAccount { @Input() bankName: string; @Input('account-id') id: string; // this property is not bound, and won't be automatically updated by Angular normalizedBankName: string; } /* B */ @Component({ selector: 'app', template: ` <bank-account bank-name="RBC" account-id="4747"></bank-account> `, directives: [BankAccount] }) class App {} bootstrap(App);
在一個指令組件的類里使用@Input() 對一個變量進行申明,被申明的變量可以通過指令的屬性進行單向數據綁定。
@Input 有一個參數,綁定dom的屬性名,如上面代碼: @Input('account-id') id: string;
dom屬性名account-id和類的id變量進行了綁定,<bank-account account-id="4747">
未帶參數的屬性名默認用變量名 @Input() bankName: string; <bank-account bank-name="RBC">
這樣就實現組件之間的通信和綁定了。
在angular1中,directive中定義屬性scope,達到scope作用域之間的數據綁定,和angular2中的@Input功能類似
scope : { bankName : "=", accountId : "=" }
<directive bank-name="RBC" account-id="4747"></directive>
@Output和@Input相反
OnInit&constructor
OnInit和 constructor都能實現初始化時候執行,constructor執行在ngOnInit之前。但他們的概念不同。
import {OnInit} from '@angular/core';
export class AppComponent implements OnInit{
constructor(){
//do something
}
ngOnInit(){
//do something
}
}
route:
配置路由,需要引入 RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS 。
- RouteConfig用於定義路由配置
- ROUTER_DIRECTIVES提供指令( [routerLink]<router-outlet> )
- ROUTER_PROVIDERS 提供路由服務
import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from '@angular/router-deprecated'; @Component({ selector: 'my-app', template: ` <h1>{{title}}</h1> <a [routerLink]="['Heroes']">Heroes</a> <router-outlet></router-outlet> `, directives: [ROUTER_DIRECTIVES], providers: [ ROUTER_PROVIDERS, HeroService ] }) @RouteConfig([ { path: '/heroes', name: 'Heroes', component: HeroesComponent } ])
[routerLink]用於指定載入鏈接,會對應 @RouteConfig 的 name 屬性,
找到 name 之后修改路由,並顯示相應UI組件,最終載入到<router-outlet>標簽下。
使用router-outlet,UI組件將會自己創建selector標簽,將組件加載到router-outlet標簽下。

默認路由&路由傳參:
@RouteConfig([ { path: '/detail/:id',//可以通過此方式傳參 name: 'HeroDetail', component: ComponentA, useAsDefault: true //設置默認路由,錯誤訪問地址都將訪問默認路由 } ])
如上代碼:ComponentA 要接收參數,需要導入RouteParams
import { RouteParams } from '@angular/router-deprecated'; RouteParams是一個class,ComponentA 初始化時候,
constructor(private routeParams: RouteParams)進行定義, 在constructor或者ngOnInit方法體里,使用 this.routeParams.get('id') 進行參數獲取。
import { RouteParams } from '@angular/router-deprecated';
export class ComponentA{
constructor(private routeParams: RouteParams){
console.log("id:", this.routeParams.get('id'))
}
}
通過Router手動跳轉頁面:
import { Router } from '@angular/router-deprecated';
class xxx{
constructor(private router:Router){}
go(){
this.router.navigate(['HeroDetail', { id: this.id }]);//參數1路由名稱,參數2參數
}
}
事件綁定:
綁定一個事件流,在組件之間通信。
自定義事件open,在 “組件A” 中定義一個事件 open , 通過 “組件B” 的標簽屬性綁定 open , 通過 “組件B” 觸發
//Component A @component { template: '<b (open)="open($event)"></b>' } class A{
open(){
console.log('done');
}
} //Conponent B import { Component, EventEmitter, Output } from '@angular/core'; class B{ @Output() open= new EventEmitter(); this.open.emit();//emit也可以傳參 }
(open)="open($event)",自定義open方法里必須要帶上$event,否則不會執行,至於為什么之后再研究。
如果是(click) 這種綁定瀏覽器默認事件,(click)="open()",就可以不用傳$event。
小結:
在使用ng2或者說使用ts開發的ng2時,會寫入更多的代碼用於申明、依賴、定義類型等,比如import,@Input,@Output,在開發的時候會覺得很麻煩,
但是這種嚴格的規范帶來的就是更高的可維護性,比如import雖然可能會寫很多,但是后期維護某個組件的時候就能很清楚的知道當前組件使用了哪些模塊。
編譯的時候angular2遵循嚴格模式,能夠幫助避免一些代碼錯誤和不規范。
這趟 “英雄之旅“ 僅僅是一個開始,見識了angular2核心、常用的api、組織結構和代碼風格。還有很多內容是需要去專研和理解。
雖然涉及不深,但是已經明顯感覺到,一些angular1中的不足,在angular2中已經不存在了。
