---
# System prepended metadata

title: Angular 初步了解

---

# Angular 初步了解

![image](https://hackmd.io/_uploads/SyqsbjqIC.png)


## Angular專案

https://github.com/lmame/Angular-HelloWorld

`src/app/app.component.ts`

```typescript=
import { Component } from '@angular/core';

@Component({ 
  selector: 'app-component',
  template: `
    <h1>Hello World</h1>
  `
})
export class AppComponent {
  
  constructor() {

  }
  
}
```

## 資料傳遞

https://ithelp.ithome.com.tw/articles/10231474

### 父層傳給子層

#### ChildComponent

```typescript=
import { Component, OnInit, Input } from '@angular/core';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
  @Input() bankName: string;
  @Input() accountId: number;
  constructor() { }
  ngOnInit(): void {
  }
}
```

```html=
<p>{{ bankName }}</p>
<p>{{ accountId }}</p>
```

#### ParentComponent

```typescript=
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
  bankName = 'ABC Bank';
  accountId = 123456789;
  constructor() { }
  ngOnInit(): void {
  }
}
```

```html=
<app-child [bankName]="bankName" [accountId]="accountId"></app-child>
```

#### 結果

![image alt](https://ithelp.ithome.com.tw/upload/images/20200520/20112573DvzrzqS8xb.png)

### 子層傳給父層

#### ChildComponent

```typescript=
import { Component, OnInit, EventEmitter, Output } from '@angular/core';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {
  @Output() counterEvt = new EventEmitter<string>();
  constructor() { }
  ngOnInit(): void { }
  counterChange(cal: string) {
    this.counterEvt.emit(cal);
  }
}
```

```html=
<button (click)="counterChange('add')">加</button>
<button (click)="counterChange('minus')">減</button>
```

#### ParentComponent

```typescript=
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit {
  counter = 0;
  constructor() { }
  ngOnInit(): void {
  }
  counterCal(cal: string) {
    cal === 'add' ? this.counter++ : this.counter--;
  }
}
```

```html=
<p>counter : {{ counter }}</p>
<app-child (counterEvt)="counterCal($event)"></app-child>
```

#### 結果

![image alt](https://i.imgur.com/LWvU14q.gif)

### 父層呼叫子層內的方法

#### ChildComponent

```typescript=
import { Component, OnInit } from '@angular/core';
@Component({
  selector: 'app-child',
  templateUrl: './child.component.html',
  styleUrls: ['./child.component.scss']
})
export class ChildComponent implements OnInit {

  seconds = 0;
  timer: any;
  constructor() { }
  ngOnInit(): void { }

  start() {
    this.timer = setInterval(() => {
      this.seconds++;
    }, 1000);
  }

  stop() {
    clearInterval(this.timer);
  }
}
```

#### ParentComponent

```typescript=
import { Component, OnInit, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from '../child/child.component';

@Component({
  selector: 'app-parent',
  templateUrl: './parent.component.html',
  styleUrls: ['./parent.component.scss']
})
export class ParentComponent implements OnInit, AfterViewInit {
  @ViewChild(ChildComponent) childComponent: ChildComponent;
  constructor() { }
  ngOnInit(): void {
  }
  seconds() {
    return 0;
  }

  ngAfterViewInit() {
    setTimeout(() => {
      this.seconds = () => this.childComponent.seconds;
    }, 1000);
  }

  onStart() {
    this.childComponent.start();
  }
  onStop() {
    this.childComponent.stop();
  }
}
```

```html=
<button (click)="onStart()">start</button>
<button (click)="onStop()">stop</button>
<p>{{ seconds() }}</p>
<app-child></app-child>
```

#### 結果

![image alt](https://i.imgur.com/6KdpUXx.gif)

### 不相關元件




## Decorators

### 基本的Decorators
Angular 的裝飾器（Decorators）是一種特殊類型的聲明，它們能夠被附加到類聲明、方法、屬性或參數上，用於修改或擴展類的行為。裝飾器是 TypeScript 的一個功能，但 Angular 對其進行了擴展，使其成為框架定義組件、服務、指令等的核心部分。以下是 Angular 中一些常用裝飾器的詳細說明：
1. **@Component**：
   - 用於定義一個組件，並指定組件的選擇器、模板、樣式等元數據。
   - 示例：
     ```typescript
     @Component({
       selector: 'app-my-component',
       templateUrl: './my-component.component.html',
       styleUrls: ['./my-component.component.css']
     })
     export class MyComponent {}
     ```

2. **@NgModule**：
   - 用於定義 Angular 模塊，它將組件、指令、服務等打包在一起。
   - 示例：
     ```typescript
     @NgModule({
       declarations: [AppComponent, MyComponent],
       imports: [BrowserModule, FormsModule],
       providers: [MyService],
       bootstrap: [AppComponent]
     })
     export class AppModule {}
     ```

3. **@Injectable**：
   - 標記一個類作為服務的類，這樣它就可以被 Angular 的依賴注入系統管理。
   - 示例：
     ```typescript
     @Injectable({
       providedIn: 'root'
     })
     export class MyService {}
     ```

4. **@Input** 和 **@Output**：
   - `@Input` 用於定義一個輸入屬性，允許從父組件向子組件傳遞數據。
   - `@Output` 用於定義一個事件發射器，允許子組件向父組件發送事件。
   - 示例：
     ```typescript
     @Component({
       selector: 'app-child',
       template: `<h1>{{data}}</h1>`
     })
     export class ChildComponent {
       @Input() data: string;
       @Output() dataChange = new EventEmitter<string>();
     }
     ```
5. **@Directive**：
   - 用於定義一個指令，指令是一種用於操作 DOM 元素的類。
   - 示例：
     ```typescript
     @Directive({
       selector: '[appHighlight]'
     })
     export class HighlightDirective {
       constructor(el: ElementRef) {
         el.nativeElement.style.backgroundColor = 'yellow';
       }
     }
     ```

6. **@Pipe**：
   - 用於定義一個管道，管道是一種用於轉換數據的類。
   - 示例：
     ```typescript
     @Pipe({
       name: 'capitalize'
     })
     export class CapitalizePipe implements PipeTransform {
       transform(value: string): string {
         return value.charAt(0).toUpperCase() + value.slice(1);
       }
     }
     ```
這些裝飾器是 Angular 框架中非常重要的部分，它們提供了一種聲明式的編程方式，使得開發者可以專注於業務邏輯，同時保持程式碼的清晰和組織。

:::info
在 Angular 中，裝飾器（Decorators）是框架核心概念的一部分，用於定義和標記組件（@Component）、服務（@Injectable）、模塊（@NgModule）等。它們提供了一種聲明式的編程方式，允許框架識別和處理這些類的元數據。

理論上，如果完全不使用裝飾器，將會失去 Angular 提供的許多便利和功能，例如依賴注入、組件生命週期的處理、模塊系統等。這些都是 Angular 應用開發中不可或缺的部分。因此，雖然可以在某些情況下通過其他方式實現類似的功能（例如直接操作 DOM 來避免使用 @Directive），但這樣做會違背使用 Angular 的初衷，並且大大增加開發和維護的複雜度。

總結來說，雖然技術上可以在不使用裝飾器的情況下開發 Angular 應用，但這樣做會失去 Angular 框架提供的大部分優勢和特性，並不是一種推薦的做法。

Angular 的框架核心會根據不同的裝飾器（Decorators）調整處理數據和行為的方式。裝飾器向框架提供了關於類如何被使用和處理的元數據信息。這些裝飾器標記的類（如組件、服務、模塊等）會被 Angular 的運行時系統以特定的方式處理，從而實現框架的核心功能。以下是一些具體例子：

1. **@Component**：告訴 Angular 這是一個組件，並提供模板、樣式和選擇器等信息。Angular 會根據這些信息創建和管理組件的實例，並將其與視圖（DOM）綁定。

2. **@Injectable**：標記一個類可以被 Angular 的依賴注入系統管理。這允許 Angular 在需要時創建和提供服務的實例，並將其注入到其他組件或服務中。

3. **@NgModule**：定義了一個 Angular 模塊，指定了應用的組件、服務和其他模塊的依賴。這使得 Angular 能夠組織和啟動應用，並支持懶加載等高級功能。

4. **@Input** 和 **@Output**：分別標記組件的輸入屬性和輸出事件。這些裝飾器使得組件之間可以通過綁定到輸入屬性和訂閱輸出事件來交互數據。

這些裝飾器不僅提供了組件和服務的定義信息，還影響了 Angular 如何創建、管理和銷毀這些對象，以及它們如何與框架的其他部分（如變更檢測系統、路由器等）交互。因此，裝飾器是 Angular 框架中實現其核心功能和特性的關鍵機制。
:::

### 自定義Decorators

Angular 允許你自定義裝飾器（Decorators）。自定義裝飾器可以用於添加額外的元數據到類、方法或屬性上，從而提供更多的靈活性和擴展性。自定義裝飾器在 Angular 應用中可以用於多種用途，比如攔截和修改類的行為、添加自定義邏輯或元數據等。

自定義裝飾器基本上是一個函數，它返回另一個函數，該函數接收目標對象、屬性名稱和屬性描述符作為參數。以下是一個簡單的自定義裝飾器示例，用於記錄方法調用：

```typescript
// 定義一個簡單的自定義裝飾器
function LogMethod(target: any, propertyName: string, propertyDesciptor: PropertyDescriptor): PropertyDescriptor {
  // 保存原始方法的引用
  const method = propertyDesciptor.value;

  // 修改方法的定義
  propertyDesciptor.value = function (...args: any[]) {
    // 調用原始方法前的邏輯
    console.log(`Calling "${propertyName}" with args: ${JSON.stringify(args)}`);
    // 調用原始方法
    const result = method.apply(this, args);
    // 調用原始方法後的邏輯
    console.log(`Called "${propertyName}" and returned: ${JSON.stringify(result)}`);
    // 返回調用結果
    return result;
  };

  // 返回修改後的屬性描述符
  return propertyDesciptor;
}

class MyClass {
  @LogMethod
  myMethod(arg: string) {
    return `Processed ${arg}`;
  }
}

const myClassInstance = new MyClass();
myClassInstance.myMethod('test');
```

在這個例子中，`LogMethod` 裝飾器被用於 `MyClass` 的 `myMethod` 方法上。當 `myMethod` 被調用時，它會首先輸出調用的參數，然後調用原始的方法，最後輸出方法的返回值。

在提供的範例中，當執行 myClassInstance.myMethod('test'); 時，會有以下兩個輸出結果：

首先，由於 @LogMethod 裝飾器被應用於 myMethod 方法，當該方法被調用時，裝飾器中的邏輯會首先執行。因此，它會輸出調用該方法的參數：
```typescript
Calling "myMethod" with args: ["test"]
```
接著，原始的 myMethod 方法會被執行，並返回其結果。在這之後，裝飾器中修改後的方法會輸出原始方法的返回值：
```typescript
Called "myMethod" and returned: "Processed test"
```
因此，完整的執行結果會是：
```typescript
Calling "myMethod" with args: ["test"]
Called "myMethod" and returned: "Processed test"
```
這顯示了裝飾器如何在原始方法調用前後添加自定義的邏輯，同時保留原始方法的行為和返回值。

自定義裝飾器提供了一種強大的機制來增強和修改類的行為，但需要注意的是，過度使用裝飾器可能會使代碼變得難以理解和維護。因此，建議在實際需要時才使用自定義裝飾器。

## 與其他Web Framework比較

![image](https://hackmd.io/_uploads/HkV1Ecc8A.png)

# Vue.js - 多樣化的 JavaScript 框架

作為一個跨平臺的，高度進步的框架，Vue 成為了許多需要創建單頁應用程式的開發人員的首選。在用於開發 Web 應用程式的典型 MVC 體系結構中，Vue 充當了 View，這意味著它可以讓開發者看到資料的顯示部分。除了上面提到的基本功能之外，Vue 還有許多其它優秀功能。
我們來看看這些：
1. 容易使用
如果你一直在使用其它框架，那麼你可以輕鬆使用 Vue，因為 Vue 的核心庫專注於 View 層，你可以輕鬆地將其與協力廠商庫進行整合並與現有項目一起使用。
2. 輕便
由於 Vue 主要關注於 ViewModel 或雙向資料綁定，因此 Vue 很輕便。Vue 也具有十分基礎的文檔。Vue 用做 View 層，意味著開發者可以將它用作頁面中的亮點功能，比起全面的 SPA，Vue 提供了更好的選擇。
3. 學習曲線很低
熟悉 HTML 的開發人員會發現 Vue 的學習曲線很低，同時對於經驗較少的開發人員和初學者來說，也能夠快速地學習和理解 Vue。
4. 雙向綁定
Vue 提供了 v-model 指令（用於更新使用者輸入事件的資料），使得在表單輸入和結構元素上實現雙向綁定變得很容易。它可以選擇正確的方式來更新輸入類型相關的元素。
5. 虛擬 DOM
由於 Vue 是基於 Snabbdom 的羽量級虛擬 DOM 實現，因此 Vue 的性能有些許的提升。這是虛擬 DOM 的主要新功能之一，開發者可以直接進行更新。當你需要在實際的 DOM 中進行更改時，只需執行一次這樣的更新功能。
6. 基於 HTML 範本的語法  
Vue 允許開發者直接將渲染的 DOM 綁定到底層的Vue實例資料上。這是一個很有用的功能，因為它可以讓開發者擴展基本的 HTML 元素，來保存可複用的代碼。
 
# Angular：動態框架

Angular 是一個功能齊全的框架，支援 Model-View-Controller 程式設計結構，非常適合構建動態的單頁網路應用程式。
谷歌在2009年開發出了 Angular 並對其提供支援，Angular 包含一個基於標準 JavaScript 和 HTML 的 JS 代碼庫。Angular 設計的最初目的是作為一個使設計者能夠與後端和前端進行交互的工具。
 以下是 Angular 的部分最好的功能：
1. Model-View-ViewModel（MVVM）
為了構建用戶端Web應用程式，Angular 將原始 MVC 軟體設計模式背後的基本原理結合在一起。然而，Angular 沒有實現傳統意義上的 MVC，而是實現了  MVVM 即 Model-View-ViewModel 模式。
2. 依賴注入
Angular 帶有內置的依賴注入子系統功能，這使得應用程式易於開發和測試。依賴注入允許開發者通過請求來獲得依賴關係，而不是搜索依賴關係。這對開發人員非常有幫助。
3. 測試
在 Angular 中，可以單獨對控制器和指令進行單元測試。Angular 允許開發人員進行端到端和單元測試運行器設置，這意味著也可以從用戶角度進行測試。
4. 跨流覽器相容
Angular 的一個有趣功能是，框架中編寫的應用程式在多個流覽器都能運行良好。Angular 可以自動處理每個流覽器所需的代碼。
5. 指令
Angular 的指令（用於渲染指令的DOM範本）  可用於創建自訂的 HTML 標記。這些是 DOM 元素上的標記，因為開發者可以擴展指令詞彙表並製作自己的指令，或將它們轉換為可重用組件。
6. Deep Linking
由於 Angular 主要用於製作單頁應用程式，因此必須利用 Deep Linking 功能才能在同一頁面上載入子範本。Deep Linking 的目的是為了查看位置 URL 並安排它映射到頁面的當前狀態。
Deep Linking 功能通過查看頁面狀態並將使用者帶到特定內容，而不是從主頁中遍歷應用程式來設置 URL。Deep Linking 允許所有主要搜尋引擎，可以輕鬆的搜索網路應用程式。  
 
## Vue.js 與 Angular--哪一個最好？
究竟哪個框架是最好的 - Angular 還是 Vue？下面我們通過以下幾點來深入研究：
* 學習曲線
在學習曲線方面，Vue.js 的學習和理解相對簡單，而 Angular 則需要時間去習慣。開發人員認為這兩個框架對於專案來說都很棒，但開發者中的大多數人更喜歡使用 Vue，因為當將 Vuex 添加到項目中時，Vue 更加簡單並且可以很好地擴展  。
儘管 Vue 和 Angular 的一些語法類似，比如 API 和設計（這是因為 Vue 實際上是從 Angular 的早期開發階段中獲得啟發的），但 Vue 一直致力於在一些對於 Angular 來說很困難的方面提升自己 。開發者可以在幾個小時內用 Vue.js 構建一個特別的應用程式，但是這對 Angular 來說是不可能的。
* 靈活性
Angular 是獨立的，這意味著你的應用程式應該有一定的構造方式。Vue 則更加寬泛，Vue 為創建應用程式提供了模組化，靈活的解決方案。
很多時候，Vue 被認為是一個庫而不是框架。預設情況下，Vue 不包含路由器，HTTP 請求服務等。開發者必須安裝所需的“外掛程式”。Vue 非常靈活並且可以與大多數開發者想要使用的庫相容。
不過，也有開發人員更喜歡 Angular，因為 Angular 為其應用程式的整體結構提供了支援。這有助於節省編碼時間。
* 文檔物件模型（DOM）
Vue 通過最少量的元件重新渲染，可以將範本預編譯為純 JavaScript。這個虛擬 DOM 允許進行大量的優化，這是 Vue 和 Angular 之間的主要區別。Vue 允許使用更簡單的程式設計模型，而 Angular 則以跨流覽器相容的方式操作 DOM。
* 速度/性能
雖然 Angular 和 Vue 都提供了很高的性能，但由於 Vue 的虛擬 DOM 實現的重量較輕，所以可以說 Vue 的速度/性能略微領先。
更簡單的程式設計模型使 Vue 能夠提供更好的性能。Vue 可以在沒有構建系統的情況下使用，因為開發者可以將其包含在 HTML 檔中。這使得 Vue 易於使用，從而提高了性能。
Angular 可能會很慢的原因是它使用髒資料檢查，這意味著 Angularmonitors 會持續查看變數是否有變化。
* 雙向資料綁定
這兩個框架均支援雙向資料綁定，但與 Vue.js 相比，Angular 的雙向綁定更加複雜。Vue 中的雙向資料綁定非常簡單，而在 Angular 中，資料綁定更加簡單。
 
### 何時選擇 Vue.js？
如果你希望通過以**最簡單的方式來製作 Web 應用程式**，那麼你應該選擇 Vue。如果你的 Javascript 基礎不是太強大，或者有嚴格的開發截止日期，Vue 將是一個很好的選擇。
如果你的前端是 Laravel，那麼請選擇 Vue。Laravel 社區的開發者認為 Vue 是他們最喜歡的框架。Vue 將總處理時間縮短了50％，並釋放了伺服器上的空間。
如果是開發小規模應用或者開發時不喜歡受約束，請選擇Vue。
如果你很熟悉 ES5 Javascript 和 HTML，那麼請使用 Vue 完成你的項目。
如果你想要在流覽器中編譯範本並且使用其簡單性，使用獨立版本的Vue會很好。
如果你打算構建性能關鍵型SPA或需要功能範圍的 CSS，Vue 的單檔組件會非常完美。
 
### 何時選擇 Angular？
如果你需要**構建大型複雜的應用程式**，那麼應該選擇 Angular，因為 Angular 為用戶端應用程式開發提供了一個完整而全面的解決方案。
對於希望處理用戶端和伺服器端模式的開發人員來說，Angular 是一個不錯的選擇。開發人員喜歡 Angular 的主要原因是 Angular 能夠使他們專注於任何類型的設計，無論是 jQuery 調用還是 DOM 配置干擾。
對於開發人員創建具有多個元件和複雜需求的 Web 應用程式，Angular 也同樣適用。當你選擇Angular 時，本地開發人員會發現更容易理解應用程式功能和編碼結構。
如果你想在新專案中選擇現有元件，也可以選擇 Angular，因為你只需複製和粘貼代碼即可。
Angular 可以使用雙向資料綁定功能來管理 DOM 和模型之間的同步。這使 Angular 成為了 Web 應用程式開發的強有力的工具。
希望製作更輕更快的Web應用程式的開發人員可以利用 Angular 中的 MVC 結構和獨立的邏輯和資料元件，這有助於加速開發過程。

Vue 插值
```
{{myVariable}} 
```
Angular插值
```
{{myVariable}}
```
Vue 循環
```
<li v-repeat="items" class="item-{{$index}}">
{{myProperty}}
</li>
```
Angular 循環
```
<li ng-repeat="item in items" class="item-{{$index}}"> 
{{item.myProperty}}
</li>
```
Vue 條件
```
<div v-if="myVar"></div> 
<div v-show="myVar"></div>
```
Angular 條件
```
<div ng-if="myVar"></div>
<div ng-show="myVar"></div>
```

#### 結論
Vue.js 是羽量級的開發框架，很適合開發小規模靈活的 Web 應用程式；而 Angular 儘管學習曲線較為陡峭，但卻是構建完整複雜應用的好選擇。

## 什麼是 Typescript？

Typescript 是一種由 Microsoft 開發的開源程式語言。
它是 JavaScript 的一種超集，意味著任何有效的 JavaScript 程式碼也是 Typescript 的有效程式碼。
Typescript 為 JavaScript 新增了類型系統（型別）和其他的一些功能，例如 Interfaces、Generics、Enums 等，這些都使得開發者能更有效地撰寫大型專案。

## Typescript 與 Javascript 的區別

雖然 Typescript 與 Javascript 在許多方面都很相似，但它們之間仍存在一些重要的區別。以下將說明兩者的主要區別：

類型系統：Javascript 是動態型別的語言，意味著變數的類型可以在程式執行期間改變。而 Typescript 則是靜態型別語言，變數的類型在宣告時就已確定，這有助於在程式碼執行之前找出可能的錯誤。

編譯器：Typescript 需要編譯才能變成 Javascript 程式碼並在瀏覽器中執行。而 Javascript 無需編譯即可在瀏覽器中直接執行。

物件導向程式設計：Typescript 支援 interface、class 和 object，可以更直觀地進行物件導向程式設計。Javascript 雖然也有 class 與 object，但並無 interface，相對於 Typescript 而言物件導向程式設計的表達較不直覺。

Typescript 程式碼範例：
```
interface Person {
  name: string;
  age: number;
}

function greet(person: Person) {
  return "Hello, " + person.name;
}

let user = { name: "Alice", age: 30 };
console.log(greet(user)); // 輸出 "Hello, Alice"
```
在這個範例中，Person 是一個介面，它定義了一個物件應該有哪些屬性，以及這些屬性的型別。greet 函式接受一個 Person 型別的參數，因此，如果我們嘗試傳入一個缺少 name 或 age 屬性的物件，或者這些屬性的型別不正確，Typescript 就會在編譯階段提出警告。

