JS30 Day10

按住 shift 選取是常見的功能,使用到的工具不多,但邏輯上需要思考一下,非常有趣。


Hold Shift and Check Checkboxes

完成目標

透過 click事件中的 shift 屬性以及陣列的觀念,來做出選取多個項目的功能。

點選 checkbox 中一個欄位之後,按著 shift 再勾選任一欄位,不論是由上往下或由下往上,這之間的每個欄位都會被勾選起來。




index-START.html

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hold Shift to Check Multiple Checkboxes</title>
</head>
<body>
<style>

html {
font-family: sans-serif;
background: #ffc600;
}

.inbox {
max-width: 400px;
margin: 50px auto;
background: white;
border-radius: 5px;
box-shadow: 10px 10px 0 rgba(0,0,0,0.1);
}

.item {
display: flex;
align-items: center;
border-bottom: 1px solid #F1F1F1;
}

.item:last-child {
border-bottom: 0;
}

input:checked + p {
background: #F9F9F9;
text-decoration: line-through;
}

input[type="checkbox"] {
margin: 20px;
}

p {
margin: 0;
padding: 20px;
transition: background 0.2s;
flex: 1;
font-family:'helvetica neue';
font-size: 20px;
font-weight: 200;
border-left: 1px solid #D1E2FF;
}
</style>
<!--
The following is a common layout you would see in an email client.

When a user clicks a checkbox, holds Shift, and then clicks another checkbox a few rows down, all the checkboxes inbetween those two checkboxes should be checked.

-->
<div class="inbox">
<div class="item">
<input type="checkbox">
<p>This is an inbox layout.</p>
</div>
<div class="item">
<input type="checkbox">
<p>Check one item</p>
</div>
<div class="item">
<input type="checkbox">
<p>Hold down your Shift key</p>
</div>
<div class="item">
<input type="checkbox">
<p>Check a lower item</p>
</div>
<div class="item">
<input type="checkbox">
<p>Everything in between should also be set to checked</p>
</div>
<div class="item">
<input type="checkbox">
<p>Try to do it without any libraries</p>
</div>
<div class="item">
<input type="checkbox">
<p>Just regular JavaScript</p>
</div>
<div class="item">
<input type="checkbox">
<p>Good Luck!</p>
</div>
<div class="item">
<input type="checkbox">
<p>Don't forget to tweet your result!</p>
</div>
</div>

<script>
</script>
</body>
</html>

index-FINISHED.html

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hold Shift to Check Multiple Checkboxes</title>
</head>
<body>
<style>

html {
font-family: sans-serif;
background: #ffc600;
}

.inbox {
max-width: 400px;
margin: 50px auto;
background: white;
border-radius: 5px;
box-shadow: 10px 10px 0 rgba(0,0,0,0.1);
}

.item {
display: flex;
align-items: center;
border-bottom: 1px solid #F1F1F1;
}

.item:last-child {
border-bottom: 0;
}


input:checked + p {
background: #F9F9F9;
text-decoration: line-through;
}

input[type="checkbox"] {
margin: 20px;
}

p {
margin: 0;
padding: 20px;
transition: background 0.2s;
flex: 1;
font-family: 'helvetica neue';
font-size: 20px;
font-weight: 200;
border-left: 1px solid #D1E2FF;
}
</style>
<!--
The following is a common layout you would see in an email client.

When a user clicks a checkbox, holds Shift, and then clicks another checkbox a few rows down, all the checkboxes in-between those two checkboxes should be checked.

-->
<div class="inbox">
<div class="item">
<input type="checkbox">
<p>This is an inbox layout.</p>
</div>
<div class="item">
<input type="checkbox">
<p>Check one item</p>
</div>
<div class="item">
<input type="checkbox">
<p>Hold down your Shift key</p>
</div>
<div class="item">
<input type="checkbox">
<p>Check a lower item</p>
</div>
<div class="item">
<input type="checkbox">
<p>Everything in between should also be set to checked</p>
</div>
<div class="item">
<input type="checkbox">
<p>Try do it without any libraries</p>
</div>
<div class="item">
<input type="checkbox">
<p>Just regular JavaScript</p>
</div>
<div class="item">
<input type="checkbox">
<p>Good Luck!</p>
</div>
<div class="item">
<input type="checkbox">
<p>Don't forget to tweet your result!</p>
</div>
</div>

<script>
const checkboxes = document.querySelectorAll('.inbox input[type="checkbox"]');

let lastChecked;

function handleCheck(e) {
// Check if they had the shift key down
// AND check that they are checking it
let inBetween = false;
if (e.shiftKey && this.checked) {
// go ahead and do what we please
// loop over every single checkbox
checkboxes.forEach(checkbox => {
console.log(checkbox);
if (checkbox === this || checkbox === lastChecked) {
inBetween = !inBetween;
console.log('Starting to check them in between!');
}

if (inBetween) {
checkbox.checked = true;
}
});
}

lastChecked = this;
}

checkboxes.forEach(checkbox => checkbox.addEventListener('click', handleCheck));
</script>
</body>
</html>



學習筆記


★ shiftKey

shiftKey 事件屬性可返回一個 Boolean 值,指當事件發生時,shift 鍵是否被按下並保持住。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<body>
<p id = "test">點擊我,測試是否按下shift鍵。</p>
</body>

<script>
const test = document.getElementById("test");

function pressDown(e){
if (e.shiftKey){
alert("按了shift");
}
else{
alert("沒按shift");
}
}
test.addEventListener("click", pressDown)
</script>

*也可以替換成其他如 e.altKeye.charCode 等 event 物件的屬性。


★ 驚嘆號 ! 與雙驚嘆號 !!

驚嘆號 ! 是個邏輯運算符,名稱為 Logic NOT ,用在布林值上具有反轉 (Inverted) 的功能,雙驚嘆號 !! 就等於反轉再反轉,等於轉回原本的布林值。

  • 在 JavaScript 中,除了以下的值為 false 之外,其他都是 true

    • undefined, null
    • Boolean: false
    • Number: 0, NaN
    • String: ''

    *注意:空物件 {} 或是空陣列 [],也會視為 true

第一個 ! 的功用就是將以上的值轉為 true,其他的值轉為 false
第二個 ! 再將 true 轉為 false,false 轉為 true,也就是轉回來,確保回傳的值是布林值。

!! 的用法基本上等同於 Boolean()

範例:

1
2
3
const a = true
const b = !a // false
const c = !!a // true

經過雙驚嘆號運算後,只會單純地出現 truefalse 兩種。

在某些情況下,可以利用 !! 將變數轉型成布林值 ,減少出錯機會。例如希望0null 被視為完全相同時:

1
2
3
4
5
const a = 0
const b = null

a === b // false
!!a === !!b // true