[JS30] Day10: Hold Shift to Check Multiple Checkbox
keywords: checkbox
, shift
, select
使用 label
在原本的程式碼中,作者並沒有使用 label ,這樣在操作上會比較不方便,因為一定要點選到該 checkbox 才能勾選,因此先在 HTML 中加上 <label>
<label class="item">
<input type="checkbox" />
<p>This is an inbox layout.</p>
</label>
監聽所有的 checkbox
// STEP1: 選擇並監聽所有的 checkbox
const checkboxs = document.querySelectorAll('.inbox input[type="checkbox"]');
checkboxs.forEach((checkbox) => checkbox.addEventListener('click', checkHandler));
按住 shift 導致文字被圈選的問題
在我們把原本的 <div>
改成用 <label>
雖然可以直接點選項目(文字部分)就來勾選和取消勾選 checkbox,但卻也多了一個問題,就是當使用者按住 shift
點選文字時,會把文字圈選起來,變成沒辦法觸發 click
事件。
這時候有一個簡單的解決方式(但不是最好的),就是透過 CSS 讓使用者無法圈選文字,進而不會出現這個問題。我們可以使用 CSS 中的 user-select
這個屬性,設定好後就能夠正常觸發 click
事件:
.item {
display: flex;
align-items: center;
border-bottom: 1px solid #f1f1f1;
user-select: none;
-ms-user-select: none;
-moz-user-select: none;
-webkit-user-select: none;
}
處理 click 事件
建立處理 click 事件的 function
建立一個 function 來處理 click 事件
// STEP2-1 處理 checkbox 被 click 的事件
function checkHandler(e) {
// ...
}
辨認開始和結束的 checkbox
為了要讓使用者按住 Shift 就能勾選所有這中間的項目,我們要知道哪些是兩個 checkbox 的「中間」,因此我們建立一個變數叫做 lastCheck
這是使用者最後一次勾選時的那個 checkbox:
let lastCheck;
function checkHandler(e) {
// STEP2-2 紀錄上一次勾選的是哪個 checkbox
if (e.target.checked) {
lastCheck = e.target;
}
}
現在有了上一次點擊的 checkbox(lastCheck
),而這一次點擊的 checkBox 可以直接抓取 e.target
就表示是當前被點擊的那個 checkbox(也可以用 this
表示)。
使用迴圈修改每個 checkbox 的狀態
有了開始(lastCheck
)和結束(e.target
),我們再建立一個變數叫做 isBetween
用來判斷這個 checkbox 是不是在開始和結束之間的 checkbox。
我們用 forEach 來疊代每個 checkbox,如果是開始,就把 isBetween 設為 true,如果碰到結束,就把 isBetween 設為 false。如果 isBetween 為 true
就把該 checkbox 設為勾選:
checkBoxs.forEach((checkbox) => {
// STEP2-4 把 isBetween 開啟和關閉(第一次碰到開啟,第二次碰到關閉)
if (checkbox === lastCheck || checkbox === e.target) {
isBetween = !isBetween;
}
// STEP2-5 如果 isBetween 為 true,則把該 checkbox 勾選
if (isBetween) {
checkbox.checked = true;
}
console.log('isBetween', checkbox, isBetween);
});
我們希望只有在使用者按住 shift 且勾選某一個項目的時候才會去執行上面的迴圈,因此我們把上面的 forEach 放在 if 判斷式中:
if (e.target.checked && e.shiftKey) {
// STEP2-3 如果使用者按住 shift 且勾選某個項目
checkBoxs.forEach((checkbox) => {
// STEP2-4 把 isBetween 開啟和關閉(第一次碰到開啟,第二次碰到關閉)
if (checkbox === lastCheck || checkbox === e.target) {
isBetween = !isBetween;
}
// STEP2-5 如果 isBetween 為 true,則把該 checkbox 勾選
if (isBetween) {
checkbox.checked = true;
}
console.log('isBetween', checkbox, isBetween);
});
}
完整的 checkHandler
// STEP2-1 處理 checkbox 被 click 的事件
let lastCheck;
function checkHandler(e) {
let isBetween = false;
if (e.target.checked && e.shiftKey) {
// STEP2-3 如果使用者按住 shift 且勾選某個項目
checkBoxs.forEach((checkbox) => {
// STEP2-4 把 isBetween 開啟和關閉(第一次碰到開啟,第二次碰到關閉)
if (checkbox === lastCheck || checkbox === e.target) {
isBetween = !isBetween;
}
// STEP2-5 如果 isBetween 為 true,則把該 checkbox 勾選
if (isBetween) {
checkbox.checked = true;
}
console.log('isBetween', checkbox, isBetween);
});
}
// STEP2-2 紀錄上一次勾選的是哪個 checkbox
if (e.target.checked) {
lastCheck = e.target;
}
console.log('==========lastCheck=========', lastCheck);
}