Vite FaceBook 第三方登入

FaceBook Sdk 申請

一. 到facebook開發人員網站,點選我的應用程式
二. 點選建立應用程式
三. 點選建立應用程式
四. 點選使用Fb驗證用戶索取資料,按下確定按鈕
五. 如圖先選『我還不想連結商家資產管理組合』,讓繼續按鈕可以選取
六. 選取『前往主控台』
出現跳出框
七. 『自訂使用案例』=> Facebook 權限
八. 『自訂使用案例』 => Facebook 設定
有效得重新導向
九. 『自訂使用案例』 => Facebook 『快速入門』
1.告訴我們您的網站 2.設定 Facebook JavaScript SDK
Facebook JavaScript SDK 沒有任何需要下載或安裝的獨立檔案,您只需要將一小段一般的 JavaScript 置入 HTML 中,就會以非同步的方式將 SDK 載入頁面中。非同步載入是指不會阻擋頁面中其他元素的載入。
3.檢查登入狀態
載入您的網頁時,第一個步驟是確認用戶是否已經使用「Facebook 登入」來登入您的應用程式。呼叫 FB.getLoginStatus 來啟動這個程序。這個函式會觸發對 Facebook 的呼叫來取得登入狀態,接著呼叫您的回呼函式來傳回結果。
以下擷取自上述程式碼範例,為在頁面載入時用來檢查用戶登入狀態所執行的部分程式碼
九. 下圖Id 就是我要們獲取的重要參數
//

安裝

1
npm install --save @healerlab/vue3-facebook-login

Vue3 Facebook Login

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<script setup lang="ts">
import { HFaceBookLogin } from '@healerlab/vue3-facebook-login';
const fbAppID = ref<string>(`${import.meta.env.VITE_FB_APP_ID}`)
const onSuccess = (response) => {
// get your auth token and info
// 取得你的身分驗證令牌和訊息
}

const onFailure = () => {
// logic if auth failed
// 身份驗證失敗時的邏輯
}
</script>

<style scoped lang="scss">
.fb-button {
display: inline-block;
margin: 10px 0 10 0;
color: white;
background-color: #1967d2;
border-radius: 8px;
padding: 16px;
cursor: pointer;
}
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<HFaceBookLogin
v-slot="fbLogin"
:app-id="fbAppID"
@onSuccess="onSuccess"
@onFailure="onFailure"
scope="email,public_profile"
fields="id,name,email,first_name,last_name,birthday">
<i @click="fbLogin.initFBLogin" class="fa-brands fa-facebook"></i>
</HFaceBookLogin>
</template>



Angular Signal API

RxJS 是一個使用可觀察序列編寫非同步和基於事件的程式的函式庫。

它提供了一種核心型別,即 Observable、一些周邊型別(Observer、Scheduler、Subjects)和類似於 Array 方法(map、filter、reduce、every 等)的運算子,以便將非同步事件作為集合進行處理。

什麼是HttpClient

HttpClient 是Angular 內建專門處理AJAX的模組,負責處理用API 溝通取得資料的複雜流程。

匯入HttpClient

Angular 18 引進了一種觸發偵測變更的新方法。檢測更改完全由 Zone Js 處理。現在,偵測變化由框架本身直接觸發。
Angular 18 的新增功能
Angular 19版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
import { provideRouter } from '@angular/router';
+ import { provideHttpClient} from '@angular/common/http';
import { routes } from './app.routes';
import { provideClientHydration, withEventReplay } from '@angular/platform-browser';

export const appConfig: ApplicationConfig = {
providers: [
provideZoneChangeDetection({ eventCoalescing: true }),
+ provideHttpClient(),
provideRouter(routes),
provideClientHydration(withEventReplay())
]
};

Subscribe

推薦把它們用於事件處理、非同步程式設計以及處理多個值等場景。

接收可觀察物件通知的處理器要實現 Observer 介面

  • next:用來處理每個送達值。在開始執行後可能執行零次或多次。
  • error:用來處理錯誤通知。錯誤會中斷這個可觀察物件實例的執行過程。
  • complete:用來處理執行完畢(complete)通知。當執行完畢後,這些值就會繼續傳給下一個處理器。
1

Angular Signal API

「當我們真的有改變需要渲染的資料時,才進行渲染」,我們也可以稱他為一種「回應變化」的處理方式,也就是每次渲染,都一定會有一個主動的變化,也是我們常常講的「reactidve programming」的一種應用。
Angular 借用了 solid.js 提出的 signal 概念,我們可以把它想像成是一種資料的「訊號」,只有當這個「訊號」有發送的時候,我們才進行回應 (也就是畫面渲染),如此一來就可以提高整體應用程式的效率!

定義Signal

Signal Html

html

1
2
3
4
5
6
<div style="font-size: 80px;">{{count()}}</div>
<div class="btn_group">
<a (click)="set()" class="button set_button">設置</a>
<a (click)="add()" class="button add_button">+1</a>
<a (click)="minus()" class="button minus_button">-1</a>
</div>

Signal TS 設置更新邏輯

1
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
import { Component, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';

@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule, RouterOutlet],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
count = signal(1)
// 設置初始數
set() {
this.count.set(1)
}
// Add增加
add() {
this.count.update(c => c + 1)
}
// Minus減少
minus() {
this.count.update(c => c - 1)
}
}

計算computed Singal

computed() 會回傳一個 readonly signal,且在呼叫時需要傳入一個 callback function,在此 function 內的 signal 發生變化時,這個 callback function 就會自動被呼叫,因此我們可以在 signal 有變化時,才去根據來源 signal 產生新結果,

引入 computed, signal

1
2
3
import { Component,computed, signal } from '@angular/core';
...
counter = signal(0);

TS

定義count=>signal(值)
computed(() => { return … })

1
2
3
4
5
6
7
8
9
10
11
12

import { Component,computed, signal } from '@angular/core';

export class HomeComponent {

count = signal(2)
countPlus = computed(() => { return this.count() * this.count() })

add() {
this.count.update(() => this.count() * this.count())
}
}

Html

1
2
3
4
5
6
7
8
9
10
11
<div class="container">
<div class="flex_center">
<p class="flex_center">compouted works!</p></div>
<div class="flex_center">
<div class="flex_center">{{ count() }}</div>
<div class="flex_center">{{ countPlus() }}</div>
</div>
<div class="flex_center" >
<a class="button add_button" (click)="add()">+1</a>
</div>
</div>

Angular 環境變數

嵌套路由

1
<router-outlet></router-outlet>

this.router.navigate([‘users’]); 切換至頁面

專案內 src 新增environment 資料夾內environment.ts 與 environment.development.ts
environment.ts檔案內新增

1
2
3
4
5
export const environment = {
production:false,
webSit:'網址',
weatherApiKey: '密碼',
};

environment.development.ts檔案內新增

1
2
3
4
5
export const environment = {
production: true
webSit:'網址',
weatherApiKey: '密碼',
};

在頁面中使用

src/app/app.component.ts 內

  • 引入environment
  • 引入environment
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
+ import { environment } from '../environments/environment';
@Component({
selector: 'app-root',
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
title = 'vite_angular19_todo_project';

+ ngOnInit(): void {
+ console.log(environment.production ? 'Production' : '開發中')
+ }
}

環境變數github

Angular 子傳父「傳值」

子元件藉由@Output裝飾器定義屬性,該屬性為EventEmitter實體,可以設定要傳送的資料型別,透過事件繫結(Event Binding)通知父元件有事件發生。

子元件

1在子元件類中匯入 Output 和 EventEmitter
1
import { Output, EventEmitter } from '@angular/core';
2@Output() newPageTitle = new EventEmitter();
1
2
3
4
5
6
export class NavbarComponent implements OnInit{
@Output() newPageTitle = new EventEmitter<string>();
sendActionList(path: string) {
+ this.newPageTitle.emit(path);
}
}
舉例 ex:Navbar
TS
在子元件類中匯入 Output 和 EventEmitter
NgFor 必須載入
1
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
+ import { Component, Input, OnInit,EventEmitter, Output } from '@angular/core';
+ import { NgFor } from '@angular/common';
import { CommonModule } from '@angular/common';
import { RouterLink } from '@angular/router';
import { navListType } from '../../Type/nav';
@Component({
selector: 'app-navbar',
imports: [
+ NgFor,
CommonModule,
RouterLink
],
templateUrl: './navbar.component.html',
styleUrl: './navbar.component.scss',
})

export class NavbarComponent implements OnInit{
// 子傳父
+ @Input() sendNavLists!: navListType[];
+ @Input() sendPageTitle!: string;
+ @Input() sendIsActive!: boolean;
// 父傳子 @Output() 欄位 = new EventEmitter<屬性>();
+ @Output() newPageTitle = new EventEmitter<string>();
//點擊頁面按鈕函式
sendActionList(path: string) {
//this.欄位.emit()
+ this.newPageTitle.emit(path);
}
ngOnInit(): void {

}
}
HTML
*ngFor 陣列方式迴圈
[ngClass] 動態Class
[routerLink] 動態Class
(click) 點擊函式
1
2
3
4
5
6
7
8
 <ul  class="nav">
<li *ngFor="let item of sendNavLists ; let i = index"
[ngClass]="sendPageTitle === item.title ? 'activeNav' : ''">
<a [routerLink]="item.path"
(click)="sendActionList(item.title)"
class="cursor-pointer">{{item.title}}</a>
</li>
</ul>
父元件
Html
(newPageTitle)="actionList($event)" => @Output() 藉由newPageTitle 通訊
1
2
3
4
5
6
7
8
9
10
<app-navbar
[sendNavLists]="navLists"
[sendPageTitle]="pageTitle"
[sendIsActive]="isActive"
+ (newPageTitle)="actionList($event)"
></app-navbar>

<main class="main">
<router-outlet />
</main>

TS

1
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
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { environment } from '../environments/environment';
import { NavbarComponent } from "./components/navbar/navbar.component";
import { navListType } from "./Type/nav";

@Component({
selector: 'app-root',
imports: [
RouterOutlet,
FormsModule,
NavbarComponent,
],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})

export class AppComponent {
title = "我的網站";
navLists: navListType[] = [
{ title: 'Home' ,path:'/'},
{ title: 'Users', path: 'user' },
{title:'Login',path:'login'}
]
pageTitle: string = 'Home';
isActive: boolean = false;
+ actionList(path: string) {
+ this.pageTitle = path;
+ }
ngOnInit(): void {
console.log(environment.production ? 'Production' : '開發中')
}
}

Angular 父傳子「傳值」

組件通訊 Component Communication with @Input

有時應用程式開發需要您將資料傳送到元件。這些資料可用於自訂元件或將資訊從父元件傳送到子元件。
Angular 使用一個稱為@Input輸入的概念。這與其他框架中的 props 類似。若要建立輸入屬性,請使用@Input 裝飾器。

在本活動中,您將學習如何使用@Input 裝飾器向組件發送訊息。

Angular 父傳子「傳值」

子元件Ts

  • 引入 Input, OnInit => 註解1
  • 引入 NgFor
  • 引入 RouterLink Navbar 因為有使用RouterLink 必須引入
  • @Component() => 註解2
  • export class NavbarComponent 改為 export class NavbarComponent implements OnInit
  • export class NavbarComponent implements OnInit 內
    @Input() Object 陣列 ex.sendNavLists!: navListType[]
    @Input() string 字串 ex.sendPageTitle!: string
    @Input() boolean布林值 ex.sendIsActive!: boolean
  • ngOnInit
    用來初始化頁面內容,顯示數據綁定、設置 directive 和輸入屬性
    在第一次 ngOnChanges 完成後呼叫,只執行一次

註解1:Input 與 OnInit 顧名思義就是進入與輸出,是使用在父子層傳遞資料使用

註解2:@Component() 裝飾器告訴 Angular 這個 class 是一個 Component,而這個裝飾器裡有三個屬性:
  • selector – 我們在其他 Component 的 HTML 檔中如何用標籤選中這個 Component 並渲染。
  • templateUrl - 要到哪裡去找 HTML 檔案,預設是同個資料夾中的 "元件名稱.component.html"
  • styleUrls - 要到哪裡去找專屬這個 Component 的 CSS 檔案,預設是同個資料夾中的 "元件名稱.
  • component.css"
  • imports- 引入其他的依賴(Dependency)

子元件 Html

  • *ngFor
    是Angular 的一個結構性指令,用於在HTML模板中迭代陣列或可迭代對象的元素。它允許我們將數據動態地呈現在HTML 中,並以迭代方式生成元素。
  • [ngClass]
    動態Class狀態
  • [routerLink]
    routerLink 是Angular 的路由機制實作的Directive指示 routerLink 說明參考

子元件 寫法

@Input() 參數欄位名稱!: 屬性;
@Input() 參數欄位名稱: 屬性 |undefined;

1
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
+ import { Component, Input, OnInit,Output,EventEmitter } from '@angular/core';
+ import { NgFor } from '@angular/common';
import { CommonModule } from '@angular/common';
import { RouterLink } from '@angular/router';
interface navListType{
title: string,
path: string,
}

@Component({
selector: 'app-navbar',
imports: [
+ NgFor,
+ CommonModule,
+ RouterLink
],
templateUrl: './navbar.component.html',
styleUrl: './navbar.component.scss',
})
// 實作初始化
+ export class NavbarComponent implements OnInit{
+ @Input() sendNavLists!: navListType[];
+ @Input() sendPageTitle!: string;
+ @Input() sendIsActive!: boolean;

@Output() newPageTitle = new EventEmitter<string>();
// 點擊頁面按鈕函式
actionList(titlePage: string) {
this.newPageTitle.emit(titlePag);
}
+ ngOnInit(): void {}
}

子元件 Html

1
2
3
4
5
6
7
8
<ul  class="nav">
<li *ngFor="let item of sendNavLists ; let i = index"
[ngClass]="sendPageTitle === item.title ? 'activeNav' : ''">
<a [routerLink]="item.path"
(click)="actionList(item.title)"
class="cursor-pointer">{{item.title}}</a>
</li>
</ul>

子元件 Scss

1
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
  .nav{
list-style-type: none;
display: flex;
margin:0px auto auto auto;
padding-inline-start: 0px;
background-color: #00bcd4;

width: 100%;
max-width: 100%;
display: flex;
justify-content: center;
height: 50px;

li{
list-style-type: none;
display: flex;
margin: auto 10px;
a{
cursor: pointer;
text-decoration: none;
color:white;
}
}
}

.activeNav{
border-bottom: 1px solid white;
}

父元件

  • 載入NavbarComponent
父元件 TS
=> 載入子元件 => 以下藉由子元件@input 欄位來傳值
1
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
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { environment } from '../environments/environment';
+ import { NavbarComponent } from "./components/navbar/navbar.component";
interface navListType{
title: string,
path: string,
}
@Component({
selector: 'app-root',
imports: [
RouterOutlet,
FormsModule,
+ NavbarComponent,
],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
// NavBar 數據
+ navLists: navListType[] = [
+ { title: 'Home' ,path:'/'},
+ { title: 'Users', path: 'user' },
+ {title:'Login',path:'login'}
+ ]
+ pageTitle: string = 'Home';
+ isActive: boolean = false;
ngOnInit(): void {
console.log(environment.production ? 'Production' : '開發中')
}
}
父元件 Html

以下藉由子元件@input 欄位來傳值

  • [sendNavLists]
    是Angular 父對子傳值中的一個
  • [sendPageTitle]
    是Angular 的一個結構性指令,用於在HTML模板中迭代陣列或可迭代對象的元素。它允許我們將數據動態地呈現在HTML 中,並以迭代方式生成元素。
  • [sendIsActive]
    是Angular 的一個結構性指令,用於在HTML模板中迭代陣列或可迭代對象的元素。它允許我們將數據動態地呈現在HTML 中,並以迭代方式生成元素。
1
2
3
4
5
6
7
8
9
10
<app-navbar
[sendNavLists]="navLists"
[sendPageTitle]="pageTitle"
[sendIsActive]="isActive"
></app-navbar>

<main class="main">
<router-outlet />
</main>

navLists功能

Angular Directive(指示)

Angular Directive(指示)

Angular中的Directive 直接翻譯是指令、指示,
我個人比較喜歡指示、指引的翻譯,代表Angular看到這個特別的詞,要去做對應的事情或動作。
指令比較像在Terminal上做的輸入。

Angular中的Directive分成以下三種:

  • 元件型 Component Directive
  • 屬性型 Attribute Directive
  • 結構型 Structure Directive

元件型指示 Component Directive

什麼是元件型指示?
指的就是元件啦!

ex: < app-root >、< app-component >
含有樣板的指示,以標籤(tag)形式呈現

屬性型 Attribute Directive

屬性、樣式
屬性型指令有以下三種:

  • ngStyle
  • ngClass
  • ngModel
ngStyle

app.component.html 檔案內
[ngStyle]="{'font-size': 26 + counter + 'px'}"

1
2
3
4
<div class="container">
<h1 [ngStyle]="{'font-size': 26 + counter + 'px'}">{{counter}}</h1>
<input type="button" value="計數器+按了會變大" (click)="count()">
</div>

app.component.ts中設定屬性變數
(click)="count()"

1
2
3
4
5
6
7
8
9
import { Component } from '@angular/core';

export class AppComponent {
counter = 0;
count(){
this.counter++;
}
}

另一種寫法

ngStyle app.component.html 檔案內 [ngStyle]="getStyle()"
1
2
3
4
<div class="container">
<h1 [ngStyle]="getStyle()">{{counter}}</h1>
<input type="button" value="計數器+按了會變大" (click)="count()">
</div>
app.component.ts中設定屬性變數 (click)="count()"
1
2
3
4
5
6
7
8
9
10
11
12
import { Component } from '@angular/core';

export class AppComponent {
counter = 0;
count(){
this.counter++;
}
getStyle(){
return {('font-size': 26 + this.counter) + 'px'};
}
}

[style.font-size] 綁定style
[style.color]綁定style
[ngClass]綁定class
app.component.html 檔案內
1
2
3
4
5
<div class="container">
<h1 [style.font-size]="(26+counter)+'px'" [style.color]='"green"'>{{counter}}</h1>
<input type="button" value="計數器+按了會變大" (click)="count()">
<p [ngClass]="{highlight: counter % 2 == 0}">偶數時會有螢光背景</p>
</div>

css

1
2
3
.highlight{
background: yellow;
}

也可以改成簡短一點

1
<p [class.highlight]="counter % 2 == 0">偶數時會有螢光背景</p>

全部

1
2
3
4
5
<div class="container">
<h1 [style.font-size]="(26+counter)+'px'" [style.color]='"green"'>{{counter}}</h1>
<input type="button" value="計數器+按了會變大" (click)="count()">
<p [class.highlight]="counter % 2 == 0">偶數時會有螢光背景</p>
</div>

結構型 Structure Directive:會影響到程式流的指令

  • ngIf
  • ngSwitch
  • ngFor
ngIf
符合條件時會動態新增DOM、不符條件時動態移除(是移除而非隱藏) 若該元素被移除,若元素裡面有其他的tag或directive 也會一併被移除。 斬草除根。 app.component.html 檔案內=>HTML
1
<p *ngIf="counter % 2 == 0">偶數時整個DOM會被移除</p>
ngSwitch
app.component.html 檔案內=>HTML
1
2
3
4
5
6
7
8
9
10
<div class="container">
<h1 [style.font-size]="(26+counter)+'px'" [style.color]='"green"'>{{counter}}</h1>
<input type="button" value="計數器+按了會變大" (click)="count()">

<div [ngSwitch]="counter % 3">
<div *ngSwitchCase="1"><p>3N+1</p></div>
<div *ngSwitchCase="2"><p>3N+2</p></div>
<div *ngSwitchDefault><p>Default 三的倍數</p></div>
</div>
</div>
ngFor
*ngFor="let item of list" app.component.ts中設定屬性變數 Ts
1
2
3
4
5
6
7
8
9
10
export class AppComponent {
data = [
{SID: 'S001', name: '王大明', score: 80, 'image-url': 'https://picsum.photos/id/10/200/300', 'self-intro': '<div>大家好,我是王大明。</div>'},
{SID: 'S002', name: '林一二', score: 99, 'image-url': 'https://picsum.photos/id/20/200/300', 'self-intro': '<div>大家好,我是林一二<br>請各位多多指教。</div>'},
{SID: 'S003', name: '黃阿道', score: 54, 'image-url': 'https://picsum.photos/id/30/200/300', 'self-intro': '<div>大家好,我是黃阿道<br>我成績不太好<br>請大家多包涵。</div>'},
];


set = new Set([1, 1, 2, 3, 4, 5, 5, 5]);
}
app.component.html 檔案內=>HTML
1
2
3
4
5
6
7
8
9
10
11
12
<div class="container" *ngFor="let item of set;">
<p>{{item}}</p>
</div>
<div class="container d-flex">
<div class="student border border-dark m-5" id="student0" *ngFor="let item of data">
<p>學號: {{item.SID}}</p>
<p>姓名: {{item.name}}</p>
<img [src]="item['image-url']" alt="大頭照">
<p>分數: {{item.score}}</p>
<p class="self-intro" [innerHTML]="item['self-intro']"></p>
</div>
</div>

參考資料

Angular Binding (綁定)

內嵌繫結

app.component.ts中設定屬性變數

1
2
3
4
5
export class AppComponent {
title = 'My Website';
link = '前往Google';
url = 'https://google.com';
}

app.component.html 檔案內使用雙括號將變數宣染
{{}} 繃定

1
2
3
4
<div class="container my-5">
<h1>{{title}}</h1>
<a href="{{url}}">{{link}}</a>
</div>
app.component.ts中設定屬性變數
1
2
3
4
export class AppComponent {
a = 10;
b = 50;
}
app.component.html 檔案內直接在樣板做運算 {{算數}} 繃定

1
<p>a+b: {{a + b}}</p>

屬性繫結 property binding

[property] = ‘statement’
app.component.html 檔案內
a標籤 [routerLink] 必須引入RouterLink 在 from ‘@angular/router’
[欄位參數]繫結

1
2
3
4
<div class="container my-5">
<h1>標題</h1>
<a [routerLink]="欄位參數">Google連結</a>
</div>

Class動態樣式 [ngClass] 綁定方是等於布林值是或否 ? ‘active’ : ‘’”
綁定自定義的attribute?
app.component.html 檔案內
[attr.data-title]繫結

1
<h1 [attr.data-title]=title>標題</h1>

事件繫結 event binding

app.component.html 檔案內
(click)事件繫結函式

1
2
3
4
<div class="container my-5">
<input type="button" value="更換標題" (click)="changeTitle()">
<h1>{{title}}</h1>
</div>

app.component.ts中設定屬性變數
點擊函式改變title

1
2
3
4
5
6
export class AppComponent {
title = 'My Website';
changeTitle(){
this.title = '更換後的標題';
}
}

傳入事件參數$event

app.component.html 檔案內
點擊函式傳入參數$event

1
2
3
4
5
6
<div class="container my-5">
<input type="button"
value="更換標題"
(click)="changeTest($event)">
<h1>{{title}}</h1>
</div>

app.component.ts中設定屬性變數

1
2
3
4
5
6
7
export class AppComponent {
title = 'My Website';
changeTest($event: any) {
console.log($event)
this.title = 'Lara換後的標題';
}
}

雙向繫結 two-way binding

[(ngModel)] = ‘property’

雙向繫結能同時做到屬性繫結()以及事件繫結[],所以符號是[()]用他來繫結某個property
app.component.html 檔案內
表單[()] 綁定

1
2
3
<input type="text" value="" placeholder="請輸入點什麼吧" [(ngModel)]="text">
<p>您的輸入: <span>{{text}}</span></p>
<p>字數: <span>{{text.length}}</span></p>

app.component.ts中設定屬性變數

1
2
3
4
5
6
7
8
9
10
11
12
13
import { Component } from '@angular/core';
+ import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-root',
imports: [
+ FormsModule
],
templateUrl: './app.component.html',
styleUrl: './app.component.scss'
})
export class AppComponent {
+ text="text"
}

Angular Pipe 管道元件

  • AsyncPipe:從非同步原語中解開一個值。
  • CurrencyPipe:將數字轉換為貨幣字串,並根據確定群組大小和分隔符號、小數點字元和其他特定於區域設定的配置的區域設定規則進行格式化。
  • DatePipe:根據區域設定規則格式化日期值。
  • DecimalPipe:根據數字選項和區域設定規則格式化值。區域設定決定群組大小和分隔符號、小數點字元以及其他特定於區域設定的配置。
  • JsonPipe:將值轉換為 JSON 格式的表示形式。對於調試很有用。
  • KeyValuePipe:將物件或映射轉換為鍵值對的陣列。
  • LowerCasePipe:將文字轉換為全部小寫。
  • PercentPipe:將數字轉換為百分比字串,並根據確定群組大小和分隔符號、小數點字元和其他特定於語言環境的配置的語言環境規則進行格式化。
  • SlicePipe:建立一個包含元素子集(切片)的新陣列或字串。
  • TitleCasePipe:將文字轉換為標題大小寫。將每個單字的首字母大寫,並將其餘部分轉換為小寫。單字由任何空白字元(如空格、製表符或換行符)分隔。
  • UpperCasePipe:將文字轉換為全部大寫。

AsyncPip從非同步原語中解開一個值。

非同步管道訂閱 ObservablePromise 並傳回其發出的最新值。當發出新值時,非同步管道會標記要檢查變更的元件。當組件被銷毀時,非同步管道會自動取消訂閱以避免潛在的記憶體洩漏。當表達式的參考發生變化時,非同步管道會自動取消訂閱舊的 Observable 或 Promise,並訂閱新的。
This example binds a Promise to the view. Clicking the Resolve button resolves the promise.
此範例將 Promise 綁定到視圖。點擊“解決”按鈕即可解決該承諾。
參考AsyncPipe官網

引入AsyncPipe

1
{{ obj_expression | async }}

example

1
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
import { AsyncPipe } from '@angular/common';
@Component({
selector: 'async-promise-pipe',
template: `<div>
<code>promise|async</code>:
<button (click)="clicked()">{{ arrived ? 'Reset' : 'Resolve' }}</button>
<span>Wait for it... {{ greeting | async }}</span>
</div>`,
})
export class AsyncPromisePipeComponent {
greeting: Promise<string> | null = null;
arrived: boolean = false;

private resolve: Function | null = null;

constructor() {
this.reset();
}

reset() {
this.arrived = false;
this.greeting = new Promise<string>((resolve, reject) => {
this.resolve = resolve;
});
}

clicked() {
if (this.arrived) {
this.reset();
} else {
this.resolve!('hi there!');
this.arrived = true;
}
}
}

也可以將非同步與 Observable 一起使用。下面的範例將時間 Observable 綁定到視圖。 Observable 使用目前時間不斷更新視圖。

1
2
3
4
5
6
7
8
9
10
11
12
13
import { AsyncPipe } from '@angular/common';
import { Observable, Observer } from 'rxjs';

@Component({
selector: 'async-observable-pipe',
template: '<div><code>observable|async</code>: Time: {{ time | async }}</div>',
})

export class AsyncObservablePipeComponent {
time = new Observable<string>((observer: Observer<string>) => {
setInterval(() => observer.next(new Date().toString()), 1000);
});
}

大寫 DatePipe:uppercase,小寫 LowerCasePipe:lowercase,首字大寫 TitleCasePipe:titlecase

大寫 引入UpperCasePipe import { UpperCasePipe } from '@angular/common';
1
2
3
// html
<p>{{'Hello World' | uppercase}}</p>

HELLO WORLD

小寫
引入LowerCasePipe
import { LowerCasePipe } from ‘@angular/common’;

1
2
3
// html
<p>{{'Hello World' | lowercase}}</p>

hello world
首字大寫
引入TitleCasePipe
import { TitleCasePipe } from ‘@angular/common’;

1
<p>{{ 'some string' | titlecase }}</p>

日期 DatePipe

根據區域設定規則格式化日期值。

參考DatePipePipe官網

引入UpperCasePipe
import { DatePipe } from ‘@angular/common’;

1
{{ value_expression | date [ : format [ : timezone [ : locale ] ] ] }}

ts檔案中新增以下設定

1
2
3
4
5
6
7
8
9
10
11
+ import { DatePipe} from '@angular/common';

@Component({
selector: 'app-test-list',
+ imports: [DatePipe],
templateUrl: './test-list.component.html',
styleUrl: './test-list.component.scss'
})
export class TestListComponent implements OnInit {
now :number= Date.now();
}
| date
html
1
<td>{{now  | date  }} </td> 
顯示:Apr 4, 2025
| date | uppercase
1
<p>{{now | date | uppercase }}</p> 
顯示:APR 4, 2025
| date: 'short':'+0000'
1
<p> {{now | date: 'short':'+0000' }}</p> 
顯示:4/4/25, 6:35 AM
| date:'yyyy-MM-dd HH:mm:ss'
1
<p> {{now |  date:'yyyy-MM-dd HH:mm:ss' }}</p> 
顯示:2025-04-04 06:35:34
| date: 'short'
1
<p> {{now | date: 'short' }}</p> 
顯示:4/4/25, 2:35 PM
| date: 'medium'
1
<p> {{now | date: 'medium' }}</p> 
顯示:Apr 4, 2025, 2:35:34 PM
| date: 'long'
1
<p> {{now | date: 'long' }}</p> 
顯示:April 4, 2025 at 2:35:34 PM GMT+8
| date: 'full'
1
<p> {{now | date: 'full' }}</p> 
顯示:Friday, April 4, 2025 at 2:35:34 PM GMT+08:00

貨幣 (CurrencyPipe)

將數字轉換為貨幣字串,並根據確定群組大小和分隔符號、小數點字元和其他特定於區域設定的配置的區域設定規則進行格式化。
CurrencyPipe公式

1
{{ value_expression | currency [ : currencyCode [ : display [ : digitsInfo [ : locale ] ] ] ] }}
引入UpperCasePipe import { CurrencyPipe } from '@angular/common';
1
2
3
4
5
6
7
8
9
10
11
+ import {  CurrencyPip} from '@angular/common';

@Component({
selector: 'app-test-list',
+ imports: [ CurrencyPip],
templateUrl: './test-list.component.html',
styleUrl: './test-list.component.scss'
})
export class TestListComponent implements OnInit {
}

| currency
html
1
<p> {{50000 | currency}}</p>
顯示:$50,000.00
| currency:'TWD':true
html
1
<p> {{50000 | currency:'TWD':true}}</p> 
顯示:NT$50,000.00
| currency:'TWD':'TWD'
html
1
<p> {{50000 | TWD50,000.00}}</p> 
顯示:TWD50,000.00
| currency:'TWD':'TWD':'4.1-3'
digitsInfo:數字顯示方式 (String)
  • minIntegerDigits:小數點前的最小整數位數。默認值為1
  • minFractionDigits:小數點後的最少位數。默認值為2
  • maxFractionDigits:小數點後的最大位數。默認值為2
html
1
<p>{{987.1234 | currency:'TWD':'TWD':'4.1-3'}}</p>
顯示:TWD0,987.123
1
2
3
4
<p>{{ 0.259 | currency: 'CAD' }}</p>
<p>{{ 1.3495 | currency: 'CAD' }}</p>
<p> {{ 0.259 | currency: 'CAD' : 'code' }}</p>
<p> {{ 1.3495| currency: 'CAD' : 'symbol' : '4.2-2' }}</p>

SlicePip

建立一個包含元素子集(切片)的新陣列或字串。
參考官網SlicePip資料

引入SlicePipe
import { SlicePipe } from ‘@angular/common’;

1
2
3
4
5
6
7
8
9
10
+ import {SlicePipe} from '@angular/common';
@Component({
selector: 'app-test-list',
+ imports: [ SlicePipe],
templateUrl: './test-list.component.html',
styleUrl: './test-list.component.scss'
})
export class TestListComponent implements OnInit {
collection: string[] = ['a', 'b', 'c', 'd'];
}

使用公式

1
{{ value_expression | slice : start [ : end ] }}

html

1
2
3
<ul>
<li *ngFor="let i of collection | slice: 1 : 3">{{ i }}</li>
</ul>

顯示:

  • b
  • c

DecimalPipe

根據數字選項和區域設定規則格式化值。區域設定決定群組大小和分隔符號、小數點字元以及其他特定於區域設定的配置

參考官網DecimalPipe資料

1
2
3
4
5
6
7
8
9
10
+ import {DecimalPipe} from '@angular/common';
@Component({
selector: 'app-test-list',
+ imports: [DecimalPipe],
templateUrl: './test-list.component.html',
styleUrl: './test-list.component.scss'
})
export class TestListComponent implements OnInit {
testNumber:number=3.14159;
}

html

1
<p>{{ testNumber| number  }}</p>

顯示:3.141

小數點建議定義參數後 .toFixed(5)

1
2
3
testNumber:number=3.14159;

{{ testNumber.toFixed(5) }}

自定義 Pipe

  • 新增pipe 功能ts名稱
    • 引入:Pipe, PipeTransform
    • @Pipe({名稱:功能})
    • export class FormatTaiwanYearPipe implements PipeTransform
    • transform(date: number | any) {.... return ....}
ˊ

範例:民國年

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { Pipe, PipeTransform } from '@angular/core';

@Pipe({
name: 'TaiwanYear'
})

export class FormatTaiwanYearPipe implements PipeTransform {
transform(date: number | any) {
let d = new Date(date),
year = d.getFullYear() - 1911,
month = (d.getMonth()+1 < 10 ? '0'+(d.getMonth()+1) : d.getMonth()+1) ,
day = (d.getDate()< 10 ?'0'+d.getDate():d.getDate()),
hour=(d.getHours()<10?'0'+d.getHours():d.getHours()) ,
minutes = (d.getMinutes()<10?'0'+d.getMinutes():d.getMinutes())

return [year, month, day].join('-')+' '+ [hour,minutes].join(':');
}
}

頁面使用

  • 引入類名稱
1
2
3
4
5
6
7
8
9
import { FormatTaiwanYearPipe } from '存放位址';

@Component({
imports: [FormatTaiwanYearPipe],
})

export class TestListComponent implements OnInit {
nowTimeStamp:number =Date.now()
}
1
2
3
4
<p >
{{ nowTimeStamp | TaiwanYear }}
</p>

github

Angular 元件執行順序 & 生命週期

ng cli產出的元件,底下都會有以下兩個方法(Method)

  • constructor Typescript的構建物件函式
  • ngOnInit Angular元件初始化時執行
執行結果
  • constructor 構建一個物件首先執行的函式,在這裡引入物件所需用到的服務
  • ngOnInit 生命週期 元件初始化,進入此元件做的事情,此時畫面尚未生成完畢
  • ngAfterViewInit 生命週期 當畫面(View)渲染完畢才做的事 例如抓取頁面上的某個節點,若在畫面出現之前執行的話會抓不到元素而變成undefined
  • ngOnDestroy 生命週期 離開、結束此元件時做的事情 刷新頁面或離開頁面都不會觸發效果 因為是這兩件事情主導權不在Angular手上,而是由瀏覽器銷毀 在未來提及Rouing切換頁面元件時可以看到效果

以人類的生命週期來對應的話,分別是

  • 受精階段: constructor 建構胚胎卵,注入所需要的養分服務,以幫助未來成長
  • 胎兒階段: ngOnInit 元件在媽媽的肚子裡面長好了
  • 嬰兒階段: ngAfterViewInit 畫面生出來了,我們肉眼看的見四肢了
  • 死亡階段: destroy 生命離開肉體軀殼,被大自然回收了