事件 (EventEmitter)
事件繫結 (Event Binding)
事件(Event) 可以說是一種狀態的描述,它提供一個主動通知的機制,讓我們可以在發生的當下去做一些額外的處理,例如:按下按鈕,這應該是我們最常用了事件,在點擊按鈕後我們可能儲存目前資訊、切換目前頁面、顯示額外訊息…等等。
在 Angular UI:標題列 我們從官方範例一起複製了一段代碼-(click)="sidenav.open()"
,看起來就像是點擊事件,但是又跟 DOM 的點擊事件(onclick
)比起來少了最前面的 on
多了小括弧。
Angular 內建透過指令(Directive)方式產生了相對應 DOM 事件的 偽事件 (不是正確觀念,但是這樣說好像比較好理解), 它本身會去監控 DOM 的事件,當 DOM 事件觸發時在去觸發對應的 偽事件,初期我們可以直接把它當作 DOM 事件來看待,只是寫法上稍做調整。
小括號 其實是 Angular 單向繫結(事件繫結)的語法,透過繫結方式讓 前端樣板(xxx**.component.html**) 的變化( 偽事件的觸發) 可以反應回 後端元件(xxx**.component.ts**)。
建立自訂事件
我們在 src\app\home\header\header.component.ts
內宣告一個事件觸發器(EventEmitter),並透過 @Output()
這個裝飾器將它提供給外部引用,並建立一個 sidenav_click 方法來觸發 EventEmitter。
@Output()
可以加入別名參數,外部會引用到此別名,它會直接對應到原本的參數,預設別名與參數相同,一般除非是特別規畫過,否則直接使用預設值在維護上會比較方便。
header.component.ts1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import { Component, OnInit, Output, EventEmitter} from '@angular/core';
@Component({ selector: 'app-header', templateUrl: './header.component.html', styleUrls: ['./header.component.scss'] }) export class HeaderComponent implements OnInit { @Output() sidenavClick = new EventEmitter();
constructor() { }
ngOnInit() { }
sidenav_click() { this.sidenavClick.emit(null); } }
|
開啟 src\app\home\header\header.component.html
將 menu 按鈕複製過來,將 click
改連結到 sidenav_click
方法,這樣 HeaderComponent 就多了一個 sidenavClick 的事件。
header.component.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <md-toolbar color="primary"> <button md-icon-button (click)="sidenav_click()" fxHide fxShow.xs> <md-icon>menu</md-icon> </button> <span>Angular demo</span> <span fxFlex></span> <button md-icon-button mdTooltip="首頁" routerLink="/home"> <md-icon>home</md-icon> </button> <button md-icon-button mdTooltip="設定"> <md-icon>settings_input_component</md-icon> </button> <button md-icon-button mdTooltip="關於"> <md-icon>info</md-icon> </button> </md-toolbar>
|
開啟 src\app\home\home.component.html
,移除 menu 按鈕,並將 sidenav.open()
繫結至 HeaderComponent 的 sidenavClick。
home.component.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <div fxFill fxLayout="column" class="layout"> <div class="header" fxLayout="row">
<app-header fxFlex (sidenavClick)="sidenav.open()"></app-header> </div> <div fxFlex fxLayout="row" class="main"> <div fxFlex="200px" class="aside" fxHide.xs> <app-aside></app-aside> </div> <md-sidenav-container fxFlex> <md-sidenav #sidenav mode="over" class="aside" fxHide fxShow.xs> <app-aside fxFlex="200px"></app-aside> </md-sidenav> <div fxFlex class="content"> <router-outlet></router-outlet> </div> </md-sidenav-container> </div> </div>
|
以手機尺寸執行瀏覽器查看結果。
同樣方式我們在 AsideComponent 元件內建立一個 menuClick 事件,並讓它在點選功能選單時觸發。
aside.component.ts1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| import { Component, OnInit, Output, EventEmitter } from '@angular/core';
@Component({ selector: 'app-aside', templateUrl: './aside.component.html', styleUrls: ['./aside.component.scss'] }) export class AsideComponent implements OnInit { @Output() menuClick = new EventEmitter();
constructor() { }
ngOnInit() { }
menu_click() { this.menuClick.emit(null); } }
|
aside.component.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <md-list> <h3 md-subheader>員工專區</h3> <button md-button routerLink="./calendar" (click)="menu_click()"> <md-list-item> <md-icon md-list-icon>today</md-icon> <h4 md-line>行 事 曆</h4> </md-list-item> </button> <button md-button routerLink="./address-book" (click)="menu_click()"> <md-list-item> <md-icon md-list-icon>contact_phone</md-icon> <h4 md-line>通 訊 錄</h4> </md-list-item> </button> <button md-button routerLink="./logbook" (click)="menu_click()"> <md-list-item> <md-icon md-list-icon>border_color</md-icon> <h4 md-line>工作日誌</h4> </md-list-item> </button> <button md-button routerLink="./to-do-list" (click)="menu_click()"> <md-list-item> <md-icon md-list-icon>playlist_add_check</md-icon> <h4 md-line>待辦事項</h4> </md-list-item> </button> <button md-button routerLink="./file" (click)="menu_click()"> <md-list-item> <md-icon md-list-icon>cloud_download</md-icon> <h4 md-line>檔案下載</h4> </md-list-item> </button> <button md-button routerLink="./leave" (click)="menu_click()"> <md-list-item> <md-icon md-list-icon>weekend</md-icon> <h4 md-line>請 假</h4> </md-list-item> </button> <button md-button routerLink="./reimburse" (click)="menu_click()"> <md-list-item> <md-icon md-list-icon>attach_money</md-icon> <h4 md-line>差旅報支</h4> </md-list-item> </button> </md-list>
|
開啟 src\app\home\home.component.html
,將 sidenav.close()
繫結至 AsideComponent 的 menuClick。
home.component.html1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <div fxFill fxLayout="column" class="layout"> <div class="header" fxLayout="row">
<app-header fxFlex (sidenavClick)="sidenav.open()"></app-header> </div> <div fxFlex fxLayout="row" class="main"> <div fxFlex="200px" class="aside" fxHide.xs> <app-aside (menuClick)="sidenav.close()"></app-aside> </div> <md-sidenav-container fxFlex> <md-sidenav #sidenav mode="over" class="aside" fxHide fxShow.xs> <app-aside fxFlex="200px" (menuClick)="sidenav.close()"></app-aside> </md-sidenav> <div fxFlex class="content"> <router-outlet></router-outlet> </div> </md-sidenav-container> </div> </div>
|
重新執行瀏覽器查看結果,現在點選功能選單時 sidenav 就會自己藏起來,整體效果應該跟一般手機APP操作差不多了。
[**first-app_2017-09-07.zip**](/uploads/first-app_2017-09-07.zip)