iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 3
0
Modern Web

Angular新手村學習筆記(2019)系列 第 3

Day03_Component_Part1

  • 分享至 

  • xImage
  •  

[S06E02] Component Part 1

https://www.youtube.com/watch?v=ielZaY4a_Jc&list=PL9LUW6O9WZqgUMHwDsKQf3prtqVvjGZ6S&index=11

S06由Kevin Yang大大主講,藉由大大導讀文件後,我們就有能力能自己查文件了

因為Kevin Yang大大的內容蠻多的,所以還是依照讀書會分2天來寫

初學者可以先建一個空專案

ng new s06e02 # 我是選要routing,scss

建完後先看src/目錄
index.html裡的,是定義在app/app.component.ts的selector裡
一個angular專案至少會有一個component在最上層(俗稱root component)
此root component會註冊在app.module.ts的

@NgModule({ # @NgModule是裝飾子(decorator),用來結構性描述此class的metadata
  declarations: [
    AppComponent # 宣告
  ],
  imports: [
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent] # 起始的component
})

來看一下app.component.ts裡頭的@Component

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss'] # 這是陣列,可以指到多份style sheet
})

angular有多少decorator呢?

https://angular.io/api?type=decorator

  • 到https://angular.io
  • 左邊選單,選API
  • API List的TYPE選Decorator

@Component

https://angular.io/api/core/Component
可以看到所有的選項(Option),介紹比較重要的

  • changeDetection 有2種模式
    Default # CheckAlways,預設是這個,如果沒有效能問題,用Default即可
    # 當發生某事件時(API回覆,或UI操作),即檢測元件樹的每個元件的連結是否有值改變
    OnPush # CheckOnce (on demand),根據Input決定是否要檢查
  • viewProviders # 跟@NgModule裡的providers用途有些不同
  • moduleId # 使用webpack用不到
  • animation # 定義動畫
  • encapsulation # 設定css的scope
    encapsulation.Emulated # 預設,會建構css來模擬DOM與root樣式
    # Use shimmed CSS that emulates the native behavior
    encapsulation.Native # angular會模擬root,只在瀏覽器與平台有原生支援時適用
    # Use ViewEncapsulation.ShadowDom instead
    encapsulation.None # 使用全域css,不封裝
    ViewEncapsulation.ShadowDom # 使用Shadow DOM v1 來封裝 styles.
  • entryComponents # 註冊在component裡要動態載入其他component,避免ng build --prod時被排除
  • preserveWhitespaces # 刪除不必要的空白字元

@Component 繼承 Directive decorator

https://angular.io/api/core/Component#inherited-from-directive-decorator
所以適用一堆Directive decoratord的Option,來看一下@Directive的Option

  • selector
    selector: 'app-my-app', # HTML TAG的寫法
    selector: '[app-my-app]', # attribute的寫法
    (可以建一個component來觀察, ng g c my-app)

以下已不建議使用在@Component裡面,建議寫在export class MyAppComponent {...}

  • inputs
  • outputs
  • providers # 註冊service
  • exportAs # 將自己本身,對外開放
  • queries # 設定queries,用來注入Directive裡面,例如:ViewChild、ContentChild
  • host # 針對host binding、host listener

html

3個基本功

  • display var
{{ varName }}
{{ varName + '!!' }} /*可以串簡單的東西*/
  • property binding
假設name='Angular!!'
<input type="text" [value]="name" /> /*property*/
<input type="text" [attr.id]="name" /> /*attribute,attribute的名稱為id*/
最後結果會類似 <input _ngcontent-c37 type="text" id="Angular!!")>
  • event binding
1.html
<button (click)="show()">show alert</button>
2.ts
show(){ alert(''); }

事件回傳的$event有很多種,常用的property有target
若不知道是哪種event,可以console.log出來,再到MDN查看
例如:MouseEvent,在MDN右上角Search「MouseEvent」,可查相關properties
https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent

<button (click)="getEvent($event)">xxx</button>
getEvent(v){
    console.log(v); // 用mouse點,傳進來的是MouseEvent
    console.dir(v);
}

// $event.target = button // event的target,事件作用的對象
  • two way binding(簡化寫法的「語法糖」)
<input type="text" [(ngModel)]="name" /> /*值會與ts裡的name變數同步*/
可拆開寫成
<input type="text" [ngModel]="name" (ngModelChange)="name=$event" />
                   property binding   event binding       ^^^^^^故定寫法
拆開寫的使用情境:不止單純同步變數,還想要額外做一些事情
<input type="text" [ngModel]="name" (ngModelChange)="doSomething($event)" />
doSometing(value){
    console.log(value); // 多做一些事情
    this.name=value;
}

property與attribute的差異

https://itw01.com/G2YWE3X.htmlhttps://itw01.com/G2YWE3X.html
參考文章:https://itw01.com/G2YWE3X.html

  • 先講結論
    大部分情境使用property,只在很有把握的情況下使用attribute

假設有個html內容為

<input id="test" class="blue" type="radio" custom-attr="1" />
  • property(DOM)
  1. 90%情況下使用property
  2. DOM物件,DOM是javascript中的物件,可以是任意型別
  3. 操作範例,會回傳相對應的data type
// javascript語法
document.getElementById('test').id; // 取得id
document.getElementById('test').className = 'red';  // 設定class,因為js裡頭class是關鍵字,要用className來取得css的class
document.getElementById('test').checked;         // get radio button's status
document.getElementById('test').checked = true;  // set radio button's status
// 還能設定物件
$('#test').prop('foo', { age: 23, name: 'John' }); // 使用jquery設定一個名為foo的物件 document.getElementById('test').foo.age; // return number型別: 23 document.getElementById('test').foo.name; // return string型別: "John" 
// jQuery語法
$('#test').prop('checked'); // boolean 
$('#test').prop('checked', true); 
  • attribute(HTML)
  1. HTML TAG內的描述節點都是attribute
  2. attribute總是「字串型別」
  3. 用js改變值時,html的attribute的value不會跟著改變
var input = document.getElementById('search'); 
input.value = 'foo2'; 
input.getAttribute('value'); // return string: "foo" 
  1. attribute的取法
document.getElementById('test').getAttribute('custom-attr') // javascript的取法
$('#test').attr('custom-attr') // jQuery的取法

在html裡的內建結構指令

  • *ngFor
1.ts
items = [1,2,3]; // Iterable
2.html
<ul>
    <li *ngFore="let item of items"> {{ item }} </li>
</ul>
  • *ngIf
1.ts
show = false;
2.html
<button (click)="show = !show">toggle show</button>
<span *ngIf="show">show</span>
  • *ngSwitch
<div [ngSwitch]="someItem.type">
    <classA-item *ngSwitchCase="'A'" [item]="someItem"> </classA-item>
    <classB-item *ngSwitchCase="'B'" [item]="someItem"> </classB-item>
    都沒符合的時候
    <classOther-item *ngSwitchDefault [item]="someItem"> </classOther-item>
</div>
  • 2種以上的結構指令要包2層以上
不能寫成
<div *ngFor="let item of items" *ngIf="items.legth > 2">
要寫多層
<div *ngFor=...>
    <div *ngIf=...>xxx</div>
</div>

template reference

語法: #變數
此變數可以直接在html上定義,不一定要在ts裡面宣告
同一個scope裡,變數名稱不能重複。但在*ngFor裡不在此限(屬於同個scope,會包在裡)

1.html
<div #content>some text</div>
<input type="text" #v1 (keyup.enter)="showValue(v1)" />
也可以傳其他的template reference
<input type="text" #v2 (keyup.enter)="showValue(content)" />
2.ts
showValue(input: HTMLInputElement){ 
    console.log(input); // 傳入該input的本體
}
showValue(input: HTMLDivElement){ 
    input.innerHTML = 'change text'; // 把some text改成change text
}
<span *ngIf="show; else showNothing">
show
</span>

<ng-template #showNothing>
nothing to show
</ng-template>

ts

@Input

建個可重複使用的component
ng g c hello
1.hello.component.ts

import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
  selector: 'hello',
  template: `
  <h1>Hello {{ name }} </h1>
  <button (click)="doSend()">output demo</button>
  `,
  styleUrls: ['./hello.component.scss']
})
export class HelloComponent {
    @Input() nameB: string; // 外部傳進來
    @Output() send: EventEmitter<any> = new EventEmitter();
    
    doSend() {
        // EventEmitter 傳值的方式
        this.send.emit('from hello component'); // 會放在 $event
    }
}

2、在app.component.html使用

<hello [nameB]="name" (send)="getEvent($event)"></hello> 
                              ^^^^^^^^^^^^^^^  
/*
把app.component.ts的name丟進hello當@Input
用 (send)="getEvent($event) 來接 hello丟出來的Output,'from hello component'放在$event裡面

[name] 要對應 @Input() name
(send) 要對應 @Output() send

不過可以用「別名」改寫成
@Input('name') nameLongLongLong: string; // 'name'是對外,內部是使用nameLongLongLong
*/

HostBinding

import { Component, HostBinding, HostListener } from '@angular/core';
@Component({
  selector: 'hello',
  template: `
  <h1>Hello {{ name }} </h1>
  <button (click)="doSend()">output demo</button>
  `,
  styleUrls: ['./hello.component.scss']
})

export class HelloComponent {
    // 針對此component的property做binding
    @HostBinding('style.color') fontColor = 'red';
    
    // 針對此component的event做listener(監聽)
    @HostListener('click', ['$event']) // 當在appComponent對hello做click時觸發
    whenClick(event) {
        console.log(event);
    }
    
    doSend() {
        this.fontColor = 'pink';

    }
}

上一篇
Day02_Angular CLI(AngularTaiwan線上讀書會第6季-主題:新手村)
下一篇
Day04_Component_Part2
系列文
Angular新手村學習筆記(2019)33
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言