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-event 與 onclick 不建議在使用

內聯模型(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 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言