iT邦幫忙

2023 iThome 鐵人賽

DAY 10
0
Modern Web

JS30 x 鐵人30 x MDN doc系列 第 10

[Day10] - Hold Shift and Check Checkboxes(JS30 x 鐵人 30 x MDN)

  • 分享至 

  • xImage
  •  

實做一個表單,按著 shift 點擊可區間全選/取消功能

  1. 既然要點擊、又要判斷是不是按著 shift 鍵的點擊,那我們先把全部<input type="checkbox">都新增針對點擊觸發的事件監聽器,然後把event印出來觀察看看。

    const checkboxList = [...document.querySelectorAll(".item input")];
    checkboxList.forEach((node) =>
      node.addEventListener("click", (e) => console.log(e))
    );
    

    嗯,屬性琳瑯滿目,但善用搜尋ctrl+f馬上就能找到本日重點shiftKey ,什麼!你不信那麼簡單就找到了?那你按著 shift 鍵再點擊觸發一次看看,他馬上就變成 true 給你看, 眼尖的妳或頭腦聰明的你,或許已經發現可以判斷是否按著另外幾種種案件觸 發這次點擊事件,那就是:altKeyctrlKey以及metaKey,原理都是相同

  2. 既然按著 shift 鍵點擊時上次與這次點擊中間的所有checkbox都需要跟著選取或取消選取,那麼當然有一個變數需要存放上次的資料。

    那要存放什麼資料能當作位置呢?應該一想就知道! 位置? index?,剛剛不是用querySelectorAll取得所有checkbox的 NodeList 了嗎,那我們只要知道這次觸發的是在 nodeList 中的第幾個位置(馬上搬出 Day7 學到的Array.prototype.findIndex()來用,但要注意,我們在上面已經把 NodeList 解構賦值變成真正的 Array 才能使用這個 method 哦!!!),然後讓 nodeList 中介於上次 index 與這次 index 間所有的checkbox的 checked 屬性都變成這次觸發的事件中的 checked 屬性就完成囉,最後再把這次的 index 值當作下一次的上一次 index 值(有點饒舌),完整的checkHandler函式如下,

    //第一次進網頁,沒有上一次點擊位置
    let lastIndex = null;
    
    checkboxList.forEach((node) =>
    node.addEventListener("click", checkHandler)
    );
    
    function checkHandler(e) {
    //用findIndex找到這次觸發是在nodeList中的第幾個
    const currentIndex = checkboxList.findIndex((node) => node === this);
    //如果按著shift鍵點擊 且 有上一次的點擊位置才往下執行
    if (e.shiftKey && lastIndex !== null) {
    // 如果上次index比這次index大,執行這段由下往上點回來
      if (lastIndex > currentIndex) {
        for (let index = lastIndex; index > currentIndex; index--) {
          checkboxList[index].checked = this.checked;
        }
    // 如果上次index比這次index小,執行這段由上往下點下去
      } else {
        for (let index = lastIndex; index < currentIndex; index++) {
          checkboxList[index].checked = this.checked;
        }
      }
    }
    //最後再把這次的index值當作下一次觸發的上一次index值使用
    lastIndex = currentIndex;
    }
    
  3. 題外話大家會不會覺得從 index 值小到大跟從大到小點選的 for 迴圈有點礙眼呢,裡面的邏輯幾乎重複,在與工作室的大學長討論之後,他跟我分享了他在Alex 宅幹嘛 YouTube 頻道學到的以下方式,用Math.minMath.max這樣永遠確保前面是小的數字後面是大的數字,並將原陣列依此 slice 切片出要點選的 node 節點,再 forEach 依序點選即可,全部用 Array method 完成,是不是非常簡潔有力呢!如果還有其他更好解決這種狀況的解法,還煩請留言賜教!!!

    if (e.shiftKey && lastIndex !== null) {
      checkboxList
        .slice(
          Math.min(lastIndex, currentIndex),
          Math.max(lastIndex, currentIndex) + 1
        )
        .forEach((node) => {
          node.checked = this.checked;
        });
    }
    

👉Github Demo 頁面 👈

👉 好想工作室 15th 鐵人賽看板 👈

參考資料

  1. Javascript 30 官網
    https://javascript30.com/
  2. MDN 官網
    https://developer.mozilla.org/en-US/
  3. [ Alex 宅幹嘛 ] Day 10:Hold Shift and Check Checkboxes https://www.youtube.com/live/tYBwiyjC_6A?si=gSgyzlM2PMP5sQEM

上一篇
[Day9] - Dev Tools Domination(JS30 x 鐵人 30 x MDN)
下一篇
[Day11] - Custom Video Player(JS30 x 鐵人 30 x MDN)
系列文
JS30 x 鐵人30 x MDN doc30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言