iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 6
0

昨天把 TodoList 上 javascript 的部分幾乎看完了!
但 click 的部分沒有做完研究呢
先附上 Todo List - codepen

如果直接看 code 和看最後的頁面結果的話,就知道當 點擊 待辦事項的時候,待辦事項就會被改變,改變的事情也就是被寫在 function 裡。

我們都會統稱 點擊 為事件 (event) 或 點擊事件(click event),那當然還有很多與使用者互動的事件,不過原理都一樣,所以想帶大家認識(複習)一下,瀏覽器怎麼處理 事件

事件處理

javascript 是一個事件驅動(event-driven) 的語言
大家應該都很熟悉,在網路頁面上都是要做了某一項操作才會有事情產生,產生了事件 javascript 才會去處理(像是我們的 TodoList 一樣)。
javascript engine 的實作是單核(單線程)的,這也是它最大的特性之一。
雖然說是單線程但像是事件(event),網路請求(xhr)或是讀檔(filereader),這些 API 都是非同步發生的,因為這些 API 有時候會比較慢如果讓他 block 住 UI ,使用者體驗會很糟

這些異步的 API 要怎麼被執行呢?

概念圖mdn-EventLoop

  • 一個主要的 call stack (execution context stack) 主要處理同步的任務
  • 異步的 API 或線程會把執行結果放在 callback queue 裡面
    • 而這次的主題 click 被點擊時,它的 callback 也會被放在這裡
  • 當主要的 call stack 處理完它的任務時,他就會去看 callback queue 有沒有事件,然後拿出放到 call stack 中進行處理
  • 一直重複這幾個步驟

Reference

html-event vs onclick vs addEventListener

昨天有發現事件居然有三種註冊的寫法,查到了 事件處理才知道這些叫做事件處理模型,而 html-eventonclick 不建議在使用

內聯模型(Inline model)

以 todo list 為例,就是按鈕上加上 onclick

<button onclick="addTodo()" class="addBtn">新增</button>

不建議這樣寫,因為你不知道 window 有沒有定義 addTodo 這個 function,
gitbook 說彈性不好不建議使用

傳統模型

像是這樣

close[i].onclick = function() {
  var div = this.parentElement;
  div.style.display = "none";
}

不建議使用這個,擴充性不好,像是觸發設定,自定義事件都不能做到

DOM Level 2

list.addEventListener('click', function(ev) {
  if (ev.target.tagName === 'LI') {
    ev.target.classList.toggle('checked');
  }
}, false);

顧名思義加入事件監聽,當觸發事件就會執行 callback
事件監聽還多了三種方法使用

  • addEventListener: 在事件對象上加入事件監聽者
  • removeEventListener: 從事件對象移除事件監聽者
  • dispatchEvent: 送出事件給所有有訂閱的監聽者

事件捕捉與冒泡

請看圖事件捕捉

當事件產生的時候會有三個 phase

  1. Capture Phase(向下捕捉)
  2. 從 Windows 開始往下
  3. 直到 event 發生的那個 element
  4. Target Phase
  5. event 發生的 element
  6. Bubbling Phase(往上冒泡)
  7. 從 #2 的 element 開始往上冒泡

註冊事件的 params 如下

addEventListener( type, handler, phase:boolean )
phase === true 註冊事件捕捉
phase === false 註冊事件冒泡

handler(event) 中的 event

當 handler 被執行時會帶一個 event 的實例
比較常用到的 property & method 如下

  1. currentTarget
  2. 捕捉冒泡 phase 中被呼叫的 handler 的節點
  3. 例如圖上 註冊了 'click' 而 觸發了 event ,此時的 currentTarget 會是
  4. target
  5. 如果看上面的圖,這個 target 永遠指項 target phase 的那個節點
  6. preventDefault
  7. 防止原本的行為
  8. 像是 <input /> 的行為是在頁面上輸入時會有字,如果呼叫了 event.preventDefault 就無法輸入
  9. 但捕捉和冒泡還是會持續發生
  10. stopPropagation
  11. 阻止事件物件繼續捕捉或冒泡傳遞

回到 TODO

HTML

<ul id="todo-list">
  <li>第一個工作</li>
  <li class="checked">先完成這個</li>
</ul>

Javascript

var list = document.querySelector('ul');
list.addEventListener('click', function(ev) {
  if (ev.target.tagName === 'LI') {
    ev.target.classList.toggle('checked');
  }
}, false);

ul 節點被註冊了 click 冒泡 事件

li 被點擊時,事件流程會開使從上捕捉然後到達 li target
到目前為止都還沒有 handler 被執行
直到 冒泡ul 這個節點 handler 才被執行
因為 target 會指到 li 所以就可以對他做 style 的改變

而利用了 冒泡 的特性,就不用對每個 list item 節點進行註冊或者 assign onclick function ,只要註冊在比較上層的地方就可以了,因此代碼變簡潔了呢!


上一篇
Day05 - TodoList js - II
下一篇
Day07 - 讓 IIFE 來當範疇的守門員
系列文
認真學前端開發 - 以 TodoList 為例30

尚未有邦友留言

立即登入留言