iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 14
0
Modern Web

從零開始的Angular前端開發系列 第 14

# DAY 14 自訂 Directive

既然 Pipe 可以自己設計,那麼 Directive 當然也可以自己做,這邊要講的是如何自己設計一個 Attribute Directive。

Angular-CLI 的 command 我們已經很熟了,下指令建立一個 Directive:

ng generate directive <directive name>

alias:

ng g d <directive name>

跟之前一樣,Angular 會建立檔案,且修改 app.module.ts

我這邊做的功能是,按下按鈕時,按鈕上的字串會被打亂,鬆開按鈕時又換成顯示原本的字串。

完整程式碼:

// homepage.component.ts

text = '漢字的順序並不影響閱讀';
// homepage.component.html

<input type="submit" [appRandom]="text" [value]="text">
// random.directive.ts

@Directive({
  selector: '[appRandom]'
})
export class RandomDirective {
  @Input('appRandom') DOMtext: string;
  el: ElementRef;

  constructor(element: ElementRef) {
    this.el = element;
  }

  @HostListener('mousedown') onMouseDown() {
    const length = this.DOMtext.length;
    const randArr = [];

    while (randArr.length < length) { 
      const rand = Math.round(Math.random() * (this.DOMtext.length - 1));
      if (!randArr.includes(rand)) { // 產生的隨機值沒有出現再陣列中,才放進去
        randArr.push(rand);
      }
    }
    let newStr = '';
    for (const i of randArr) {
      newStr += this.DOMtext[randArr[i]];
    }
    this.el.nativeElement.value = newStr;

  }

  @HostListener('mouseup') onMouseUp() {
    this.el.nativeElement.value = this.DOMtext;
  }
}

  @Input('appRandom') DOMtext: string;
  el: ElementRef;

  constructor(element: ElementRef) {
    this.el = element;
  }

我在 RandomDirective 裡面宣告一個變數叫 DOMtext ,前面加上 @Input() 這個 Decorator,所以外部可以用 Property Binding,將變數傳入,就是 [appRandom]="text",將 text 傳進 @Input()的部分。

接著我用 ElementRef,在constructor(element: ElementRef)初始化的時候,傳入一個 element,這裡會傳入在 homepage.component.html<input>,如此一來,我們就可以直接對 DOM 進行操作,


@HostListener('mousedown') onMouseDown() {
    ...
    }
@HostListener('mouseup') onMouseUp() {
    ...
    }

@HostListener() 用來監聽事件,像 @HostListener('mousedown') onMouseDown() 就是監聽 mousedown 這個按下滑鼠的事件,並綁定到 onMouseDown() 這個自訂的 function。@HostListener('mouseup') onMouseUp() 則是監聽滑鼠鬆開的事件。

@HostListener('mousedown') onMouseDown() {
    const length = this.DOMtext.length;
    const randArr = [];

    while (randArr.length < length) {
      const rand = Math.round(Math.random() * (this.DOMtext.length - 1));
      if (!randArr.includes(rand)) {
        randArr.push(rand);
      }
    }
    let newStr = '';
    for (const i of randArr) {
      newStr += this.DOMtext[randArr[i]];
    }
    this.el.nativeElement.value = newStr;
  }

中間一大段程式,是我根據 DOMtext ,產生一個一樣長度的陣列,裡面放的是打亂的 index,再根據這個 index,產生一個新的、隨機排列過的字串。

先用 Math.random() 產生 0 ~ 1的浮點數,再乘上length - 1。假設我的字串長度是 12,那我需要產生範圍 0 ~ 11 的亂數,所以會是 length - 1,最後再用 Math.round() 做四捨五入,最後我就能生出一些這樣的陣列:

再用這個陣列的順序,將舊的字串,依照順序,每個字新增到 newStr  後面,就可以得到一個隨機排列過的字串。

最後用 this.el.nativeElement.value = newStr; 改變 DOM顯示的 value,所顯示的就會是新的字串。

當我放開滑鼠時,再將原先的 this.DOMtext,送到 DOM 的 value,讓它顯示隨機排列前的文字,這也是為什麼我們不對 this.DOMtext 進行修改的原因。

執行結果:


上一篇
# DAY 13 Pipe
下一篇
# DAY 15 NgModule - 簡介
系列文
從零開始的Angular前端開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言