[angular2]一些名詞需知,還有快速掌握重點動手入門

讓入門的人,有方向可以知道如何學習angular這套技術

前言

因為需要帶領member如何開始入門,並大方向的懂得angular2的名詞,還有如何從官方文件參考必要的文檔,畢竟官方的文件非常的多,甚至有些光一個主題就非常的長,對入門來說過於嚴苛,要學習一套技術需要花那麼多時間,對很多每天一堆工作的人,其實也是很不切實際,那我想要快速的解釋一下必須知道的一些名詞,點到為止真的需要使用,再去官網找資料學習。

英文官網

中文官網

導覽

  1. angular的優勢
  2. 快速理解架構層面
  3. 一切先從module開始
  4. 入門component
  5. 入門template
  6. binding的幾種方式還有組件間最簡單的溝通方式
  7. 基礎入門結束,接下來該學什麼
  8. 使用自動化的方式,學習不需要死背
  9. 結論

 

angular的優勢

其實目前來說react和angular和vue對於狀態處理的方式都是一致的,所以以前為人詬病的angularjs two way binding還有效能的問題,其實在angular已經都不會再有相關問題了,那angular相對其他框架有什麼優勢呢,最大的優勢就是angular有微軟和google兩個老爸撐腰,這兩個世界最大巨頭的軟體公司,目前來說不是任何一套框架可以相提並論的,還有ide上面的支援,甚至angular都有出現了專屬的IDE(https://www.genuitec.com/products/angular-ide/),相信目前為止vue還有react都還沒有去對開發者體驗做出很大的支援,最後就是angular是個大而全的框架,就不用再浪費自己的時間去做很多元件版本的整合,在追求穩定的企業裡面這確實是很重要的。

 

快裡理解架構層面

這部份我們可以直接從Architecture(https://angular.io/docs/ts/latest/guide/),去大局的了解一下,我已較簡短的說明來解釋,如果要詳盡的解釋可以直接參考官網,我們先看一下angular所有組合的一些關鍵字詞還有圖示吧

再看一下官網羅列的主要名詞,這些名詞就是構成angular的主要關鍵

  1. Modules-可以想像成c#裡面的dll,裡面可能放著第三方或自定義的module
  2. Components-元件,也是angular最主要的部份,所有angular都是由元件組成
  3. Templates-html樣版,依附在component裡
  4. Metadata-元數據,告訴angular是一個組件或指令,不然實際上所有的ts不過就是一個類別而已
  5. Data binding-數據綁定,如何改變畫面的變化,其實就是用binding的方法,angular會檢查數據如果變了,就會針對綁定的部份做變化
  6. Directives-指令,有分結構指令或屬性指令,結構指令就是類似*ngIf
  7. Services-類別,其實這個跟下面的di是相對的,雖然可以直接用new的方式建立,但你絕對不會想要這樣做的
  8. Dependency injection-就是使用注入的方式,可以方便統一在進入點把實做換掉,而且也會自動解構類別

雖然上面很多名詞,但其實都是由component擴散出去的,所以我們入門的時候,就是先focus在元件,還有知道modules要怎麼宣告,其餘的部份再慢慢的學習,我們不需要全部學習完再動手,有時候做應用根本只是用到整個框架的30%而已,不需要一定得學到80%以上才開始動手做,如果想要深入學習各個主題,在這個Architecture的裡面都可以透過連結去探索。

 

一切先從module開始

當我們新增一個component或service或第三元元件的module,都必須要從module開始,而且這部份真的也是會常常忘記的,所以我建議就是只要你新增什麼檔案,就先從module加上去,再回去寫邏輯,當然如果我們用cli自動產生service或component的時候,正常來講都會自動幫我們加在module裡面,但有時候module變多了,專案變複雜了之後,就會不一定靈驗了,首先來看一下module的部份吧。

何謂root module呢?也就是主要的module,cli預設幫我們產生的app.module.ts這支檔案。

 

入門component

我們要學習component很簡單,只需要理解最簡單的就足夠寫應用了,需要用到再去查就好了

import { Component } from '@angular/core';

@Component({ //metadata
  selector: 'app-root', //如果在html使用,會像<app-root></app-root>
  templateUrl: './app.component.html', //可以指定html放在哪邊,./代表同層
  styleUrls: ['./app.component.css'] //指定css也可以替換成scss
})
export class AppComponent {
  title = 'app works!'; //定義數據,這邊不可用var,let,const
  countNumber: number;//可以定義型別,但也可以只給數字,會自動推斷型別
  constructor() {
    this.title = 'change title'; //得用this呼叫class的全局變數
    this.get();
    this.strongGet();
  }

  get() { //沒定義型別,typescript一樣可以使用弱型別,並沒規定一定得要強型別
    let message = 'hello'; //局部必須得宣告let or const or var
    return message;
  }

  strongGet(): string { //定義回傳的型別
    const message = 'strong hello';
    return message;
  }
}

 

入門template

template的部份就包含了指令和binding的部份,在指令的部份其實最常用的也是沒幾個ngIf,ngFor,ngModel

ngIf代表判斷這個元件是否要顯示或隱藏,但是這個指令是用新增或刪除dom的方式

ngFor就是把陣列foreach出來就對了

ngModel就是針對會讓使用者輸入值來改變數據的綁定,比如說大部份<input type="text"/>

再來則是事件了,其實在angular裡面,只要加上()就是綁定事件了其餘則是原生的javascript事件名稱,比如(click)=onclick的意思,(mouseover)=onmouseover

以這些簡單的觀念,我們就能做出新增刪除的簡單範例了,我把程式碼貼在下面供參考

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  names = [];
  name: string;

  add() {
    this.names.push(this.name);
    this.name = '';
  }

  remove(item) {
    this.names = this.names.filter(x => x !== item);
  }
}

app.component.html

<h1>this is input area</h1>
<input type="text" [(ngModel)]="name">
<input type="button" (click)="add()" value="add">
<hr>
<div *ngIf="names.length>0">
  <h1>this is display area</h1>
  <ul>
    <li *ngFor="let item of names">
      <a href="#" (click)="remove(item)">remove</a>
      {{item}}
    </li>
  </ul>
</div>

 

binding的幾種方式還有組件間最簡單的溝通方式

接著我們必須了解一下我們在angular如何做binding,其實binding的方式也很簡單,在即有的html裡面,我們只要[]就算binding,比如把剛剛ngIf改成[hidden]也是能執行,只是判斷要反過來

<h1>this is input area</h1>
<input type="text" [(ngModel)]="name">
<input type="button" (click)="add()" value="add">
<hr>
<!--<div  *ngIf="names.length>0">-->
<div [hidden]="names.length===0">
  <h1>this is display area</h1>
  <ul>
    <li *ngFor="let item of names">
      <a href="#" (click)="remove(item)">remove</a> {{item}}
    </li>
  </ul>
</div>

可以注意到hidden是原始的html的屬性,所以任何html的屬性我們只要加個中括號就能binding了,非常的簡單哦,再來就是簡單看一下組件間的溝通方式,丟進去的值有兩種方式,一種是直接丟字串,這樣子的話就不用加[],如果要讓子組件的畫面隨著父組件的值改變而去更新,就需要加上[],那如果要收到子組件的通知,就要加上(),底下就來個例子,我把剛剛那個簡單的新增刪除的例子,改成元件溝通的方式,在子組件需要宣告@Input()來接收父組件丟進來的值,這邊特別說明一下對vue或react熟悉的人應該都知道,子組件是不能異動父組件丟進來的值,在react的話會直接報錯,vue會有警告,但angular是允許這樣做的,如何好好管理狀態不是入門所需要講解的,先關注一下程式碼的部份囉

app.component.html

<h1>this is input area</h1>
<input type="text" [(ngModel)]="name">
<input type="button" (click)="add()" value="add">
<hr>
<app-list [names]="names"></app-list>

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  names = [];
  name: string;

  add() {
    this.names.push(this.name);
    this.name = '';
  }
}

list.component.html

<!--<div  *ngIf="names.length>0">-->
<div [hidden]="names.length===0">
  <h1>this is display area</h1>
  <ul>
    <li *ngFor="let item of names">
      <a href="#" (click)="remove(item)">remove</a> {{item}}
    </li>
  </ul>
</div>

list.component.ts

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

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
  @Input() names = []; //接收父組件傳進來的names
  constructor() { }

  ngOnInit() {
  }

  remove(item) {
    this.names = this.names.filter(x => x !== item);
  }
}

最後結果跟上個新增刪除的範例是一樣的,接著我們來談一下如果子組件異動了想通知父組件怎麼做呢?我們只需要用簡單的output,比如我刪除了值,我想通知上面,而不是由子組件直接異動names,而是把處理邏輯交給父組件,子組件只負責值變了後,就做更新,要通知上面就是用output,我會在需要注意的地方特別下註解哦。

app.component.html

<h1>this is input area</h1>
<input type="text" [(ngModel)]="name">
<input type="button" (click)="add()" value="add">
<hr>
<app-list [names]="names" (onRemove)="onRemove($event)"></app-list>
<!--names是丟到子組件的,onRemove則是接收子組件的通知-->

app.component.ts

import { Component } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  names = [];
  name: string;

  add() {
    this.names.push(this.name);
    this.name = '';
  }

  onRemove(item) {
    this.names = this.names.filter(x => x !== item);
  }
}

list.component.html

<!--<div  *ngIf="names.length>0">-->
<div [hidden]="names.length===0">
  <h1>this is display area</h1>
  <ul>
    <li *ngFor="let item of names">
      <a href="#" (click)="remove(item)">remove</a> {{item}}
    </li>
  </ul>
</div>

list.component.ts

import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
  @Input() names = []; //接收父組件傳進來的names
  @Output() onRemove = new EventEmitter();//通知父組件的事件
  constructor() { }

  ngOnInit() {
  }

  remove(item) {
    this.onRemove.emit(item); //通知父組件,並把按下的那一筆送出去
    // this.names = this.names.filter(x => x !== item);
  }
}

如果我們只是想要丟一個字串進去的話,就直接定義屬性就好了,比如說我想要list裡面的標題,是父組件決定的,下面程式碼只貼有異動的部份

app.component.html

<h1>this is input area</h1>
<input type="text" [(ngModel)]="name">
<input type="button" (click)="add()" value="add">
<hr>
<app-list [names]="names" (onRemove)="onRemove($event)" title="this is app defined title"></app-list>
<!--names是丟到子組件的,onRemove則是接收子組件的通知,title是傳進一個變數-->

list.component.html

<!--<div  *ngIf="names.length>0">-->
<div [hidden]="names.length===0">
  <h1>{{title}}</h1>
  <ul>
    <li *ngFor="let item of names">
      <a href="#" (click)="remove(item)">remove</a> {{item}}
    </li>
  </ul>
</div>

list.component.ts

import { Component, OnInit, Input, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'app-list',
  templateUrl: './list.component.html',
  styleUrls: ['./list.component.css']
})
export class ListComponent implements OnInit {
  @Input() names = []; 
  @Output() onRemove = new EventEmitter();
  @Input() title: string; //接收不變的字串
  constructor() { }

  ngOnInit() {
  }

  remove(item) {
    this.onRemove.emit(item); 
  }
}

 

基礎入門結束,接下來該學什麼

上面必須知道的都差不多了,接下來如果我們需要用到ajax的話,就需要參考http的入門章節(https://angular.io/docs/ts/latest/tutorial/toh-pt6.html),然後因為angular要做較完整的應用,一定需要client的路由,我們也可以從路由入門了解(https://angular.io/docs/ts/latest/tutorial/toh-pt5.html),當我們覺得所有程式碼都放在元件裡面,很難維護或者重覆的 程式碼一再出現在不同的元件之間的時候,我們就可以來了解一下service和di的入門部份(https://angular.io/docs/ts/latest/tutorial/toh-pt4.html),或者可以了解一下redux風格的ngRx( https://github.com/ngrx/store),到此要完成一個應用就沒什麼問題了,雖然還有很多主題需要去學習,但是當遇到我們再去涉獵就夠了。

 

使用自動化的方式,學習不需要死背

我們可以使用工具來自動快速產生component或service等等,我們只要安裝AngularDoc就可以在vscode建立了,不用再到cmd下指令新增,extension如圖示

操作畫面如下

我們也需要安裝snippets來方便一些語法提示,而不需要一定得靠死背或一直查官方文件確認怎麼寫,有時候我們只需要看到知道怎麼寫怎麼改,而不是一直得用背的打出來。

下面是我的一些快速產生的操作示例

關於angular有什麼我覺得可以安裝的工具,我之前也有寫一篇文章說明(https://dotblogs.com.tw/kinanson/2017/03/27/133103),但其實我個人常常會去試用各種extension,所以常常會發覺什麼可能是更好用的,所以僅供參考,如果有發現什麼更好用的,也請再介紹給筆者。

 

結論

此篇稍微長了一點,程式碼也多了一點,但其實此篇程式碼非常簡單,請花點心思體會一下,然後實際動手做一下,要入門angular真的很簡單。