###### tags: `Angular` # 🥔從認識 Component 開始 在開發專案的時候,大部分的程式邏輯我們都是寫在 Component 裡面 ,因此我想大家對於 Component 一定不陌生,但有些東西可能從來沒有注意過,或是不知道為什麼它是這個樣子。 所以我今天會從 Component 來開始,來帶大家認識 Angular 的一些基礎概念。 >[API參考手冊-Component](https://angular.tw/api/core/Component)。 ## *@Component.* 裝飾器 - 宣告的類別掛上`@Component`裝飾器,就表示此類別為一個元件。Angular的元件類別負責暴露資料,並透過資料繫結機制來處理絕大多數檢視的顯示和使用者互動邏輯。 - `@Component()`裝飾器是擴充`@Directive()`裝飾器,增加了一些與範本(`template`)有關的特性。 ## *@Component.* 資料配置 - `@Component`裝飾器內的配置,決定此元件會與哪個範本(`template`)建立關聯,與其他相關的程式,以下是`Component`基礎配置。 ```typescript= import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-first', templateUrl: './first.component.html', styleUrls: ['./first.component.css'] }) export class FirstComponent implements OnInit { constructor() { } ngOnInit() { } } ``` ## *@Input* - 負責接收資料 >**Parent傳'Hello',Child接收並顯示** >1. 建立一個child component並設計`@Input()`功能。 >2. 建立一個parent component使用child component,且使用child的`@Input()`。 *step1.* 建立Child component ==child.component.ts== ```typescript= import { Component, Input, OnInit } from "@angular/core"; @Component({ selector: "app-child", templateUrl: "./child.component.html", styleUrls: ["./child.component.css"] }) export class ChildComponent implements OnInit { @Input() strShow: string; constructor() {} ngOnInit() {} } ``` ==child.component.html== ```htmlembedded= <p>{{strShow}}</p> ``` *step2.* 建立Parent component ==parent.component.ts== ```typescript= import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-parent', templateUrl: './parent.component.html', styleUrls: ['./parent.component.css'] }) export class ParentComponent implements OnInit { strInput = 'Hello'; constructor() { } ngOnInit() { } } ``` ==parent.component.html== - 要使用child內的`@Input()`要在HTML內使用,且要用[中括號]括起來後面再帶入參數。 ```htmlembedded= <app-child [strShow]="strInput"></app-child> ``` ## *@Output* - 負責發射資料 >**Parent接收點擊按鈕後,由Child送出的'World'** >1. 建立一個child component並設計`@Output()`功能。 >2. 建立一個parent component使用child component,且使用child的`@Output()`。 *step1.* 建立Child component ==child.component.ts== - Output一定要搭配使用EventEimmter,這是固定寫法。 - emit(),就是發射訊息的意思。 ```typescript= import { Component, EventEmitter, OnInit, Output } from "@angular/core"; @Component({ selector: "app-child", templateUrl: "./child.component.html", styleUrls: ["./child.component.css"] }) export class ChildComponent implements OnInit { @Output() strWord = new EventEmitter(); constructor() {} ngOnInit() {} onClick() { this.strWord.emit('World'); } } ``` ==child.component.html== ```htmlembedded= <button (click)="onClick()">Output</button> ``` *step2.* 建立Parent component ==parent.component.ts== ```typescript= import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-parent', templateUrl: './parent.component.html', styleUrls: ['./parent.component.css'] }) export class ParentComponent implements OnInit { constructor() { } ngOnInit() { } showStrWord(strWord) { console.log(strWord); } } ``` ==parent.component.html== - 要使用child內的`@Output()`要在HTML內使用,且要用(小括號)括起來後面再帶入參數。 - `showStrWord($event)`,這裡面的`$event`是emit的值,那$event也是固定寫法。 - 可以在devTools[F12] console 看到child傳送過來的值,確認是否正確。 ```htmlembedded= <app-child (strWord)="showStrWord($event)"></app-child> ``` ## *其他傳值的方法* [[T]Passing Parameters 參數傳遞](https://hackmd.io/@Ru/BkcCsfB2H#ViewChild) - @ViewChild ==viewchild.component.html== ```htmlembedded= <h2>@ViewChild()</h2> <p>{{message}}</p> ``` ==viewchild.component.ts== ```typescript= import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-viewchild', templateUrl: './viewchild.component.html', styleUrls: ['./viewchild.component.scss'] }) export class ViewchildComponent implements OnInit { message: string = '我是土豆'; constructor() { } ngOnInit(): void { } setMessage(message: string) { this.message = message; } } ``` ==component.component.html== ```htmlembedded= <app-viewchild #vc></app-viewchild> <input [(ngModel)]="vcMsg" (change)="onChange()"> ``` ==component.component.ts== ```typescript= import { ViewchildComponent } from './viewchild/viewchild.component'; import { Component, OnInit, ViewChild, AfterViewInit, ChangeDetectorRef } from '@angular/core'; @Component({ selector: 'app-component', templateUrl: './component.component.html', styleUrls: ['./component.component.scss'] }) export class ComponentComponent implements OnInit, AfterViewInit { @ViewChild('vc') vc: ViewchildComponent; vcMsg: string; constructor( private changeDetectorRef: ChangeDetectorRef ) { } ngOnInit(): void { } ngAfterViewInit(): void { this.vc.setMessage('土豆'); this.changeDetectorRef.detectChanges(); } onChange() { this.vc.setMessage(this.vcMsg) } } ``` > `ExpressionChangedAfterItHasBeenCheckedError` > 使用 `@ViewChild` 的時候需要注意父元件的使用時機 - RouterState ==router-state.component.html== ```htmlembedded= <h2>routerState</h2> <button routerLink="/a4/component/input" [state]="{page: 'A'}">Page A</button> <button (click)="onClickB()">Page B</button> <button routerLink="/a4/component/viewchild">Page C</button> <router-outlet></router-outlet> ``` ==router.state.component.ts== ```typescript= import { Router } from '@angular/router'; import { Component, OnInit } from '@angular/core'; @Component({ selector: 'app-router-state', templateUrl: './router-state.component.html', styleUrls: ['./router-state.component.scss'] }) export class RouterStateComponent implements OnInit { constructor( private router: Router ) { } ngOnInit(): void { } onClickB() { this.router.navigate(['/a4/component/output'], {state: {page: 'B'}}) } } ``` ==input / output component.ts== ```typescript= ngOnInit(): void { console.log('state', window.history.state); } ```