目標
類似 Gmail 信箱的 checkbox 多選功能,當選取一個 checkbox 後,按住 shift 不放,在選取另一 checkbox ,此兩個 checkbox 中間的 checkbox 皆會選取。
Demo | Github
處理步驟
與範本的方法與步驟可能不太相同,依照個人的方式去解決就好。
步驟 1.
取得所有的 checkbox DOM 並綁定 click 事件,建立的 handleCheck function 中可以利用 console 查看一下 e 的物件,為 MouseEvent
1 2 3 4 5 6
| const checkboxes = document.querySelectorAll('.inbox input[type="checkbox"]'); function handleCheck(e) { console.log(e); } Array.from(checkboxes).map(ele => ele.addEventListener("click", handleCheck));
|
步驟 2.
開始針對 handleCheck function 撰寫判斷,首先是 shift 鍵按下並選取該 checkbox 時,進行全部的 checkbox DOM 巡覽。
這時候調整一下 checkboxes 變數,因為 querySelectorAll 取得的結果不是 Array ,所以先轉換
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const checkboxes = Array.from( document.querySelectorAll('.inbox input[type="checkbox"]') );
function handleCheck(e) { const self = this; if (e.shiftKey && e.target.checked) { console.info("this is shift & checked"); checkboxes.map(ele => { }); } }
checkboxes.map(ele => ele.addEventListener("click", handleCheck));
|
步驟 3.
在巡覽的過程中,加入判斷式,決定要變更 checkbox 選取狀態的變更。
- 加入 checkEle 變數紀錄 click 每次觸發後,上次的選取 DOM
- 判斷 目前觸發元素是否等於巡覽的元素,或是 checkEle 是否等於巡覽的元素,並且 checkEle 不能等於目前觸發元素
- 加入 isBetween 變數,用來記錄是否符合上述的條件
- 最後將巡覽的所有元素 checked 都設定為 true 的值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| let checkEle = null; function handleCheck(e) { const self = this; if (e.shiftKey && e.target.checked) { let isBetween = false; checkboxes.map(ele => { if ((self === ele || checkEle === ele) && checkEle && checkEle !== self) { isBetween = !isBetween; } if (isBetween) ele.checked = true; }); } checkEle = self.checked ? self : null; }
checkboxes.map(ele => ele.addEventListener("click", handleCheck));
|
延伸部分
此解法,是按照範例的方式去處理;延伸課題是仿照類似 Gmail 的選取方式選取區間,所以需要取得距離目前選取最近的選取框
- 建立 extenCheck function
- 找尋索引小於目前選取元素的索引,並且有選取的 checkbox ,取得此索引
- 找尋索引大於目前選取元素的索引,並且有選取的 checkbox ,取得此索引
- 判斷前 2 操作都是有取得索引後,直接更新選取狀態
- 抽取選取狀態 function
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
|
function extenCheck(e) { const self = this; if (!e.target.checked) return;
const nowSelIndex = checkboxes.findIndex(ele => ele === self);
if (!e.shiftKey) return;
const nearMinCheckboxIndex = checkboxes.findIndex( (ele, index) => index !== nowSelIndex && index < nowSelIndex && ele.checked === true ); const nearMaxCheckboxIndex = checkboxes.findIndex( (ele, index) => index !== nowSelIndex && index > nowSelIndex && ele.checked === true );
if (nearMaxCheckboxIndex !== -1) { setCheckbox(nowSelIndex, nearMaxCheckboxIndex); }
if (nearMinCheckboxIndex !== -1) { setCheckbox(nearMinCheckboxIndex, nowSelIndex); } }
function setCheckbox(initIndex, aryLength) { for (let index = initIndex; index < aryLength; index++) { checkboxes[index].checked = true; } }
|
參考資料