第十天挑战(计划便签)
所有内容均上传至gitee,答案不唯一,仅代表本人思路
该详解是Soyaine及其团队整理编撰的,是对源代码的详解,强烈推荐大家观看学习!!!!!!!
本人gitee:gitee.com/thats-all-r…
效果
-
样式分析
- 组件整体居中
- 组件左侧为复选框,右侧为该复选框对应的计划
- 复选框被选中时,有划线效果,文字背景加深
-
逻辑分析
- 当复选框被选中后,其对应的事项会被添加样式
- 按住Shift后,可以一次选中多个复选框并改变对应内容的样式
- 可以正相多选或反向多选(1 - 5 or 5 - 1)
本人代码及思路分析
仅提供布局及逻辑代码
结构:
input:checked + p {
background: #F9F9F9;
text-decoration: line-through;
}
<input type="checkbox">
<p>今日计划</p>
<input type="checkbox">
<p>今日计划</p>
<input type="checkbox">
<p>今日计划</p>
<input type="checkbox">
<p>今日计划</p>
<input type="checkbox">
<p>今日计划</p>
逻辑:
let g = true
const checkbox = document.querySelectorAll('input')
const checkboxs = Array.from(checkbox)
let shift = null
let indexStart
let indexEnd
checkbox.forEach(item => {
item.addEventListener('change', (e) => {
if (g) {
indexStart = checkboxs.findIndex(item => item === e.target)
}
if (shift === 'Shift') {
indexEnd = checkboxs.findIndex(item => item === e.target)
if (indexStart > indexEnd) {
checkboxs.slice(indexEnd, indexStart).forEach((item, index) => {
item.checked = true
})
} else {
checkboxs.slice(indexStart, indexEnd).forEach((item, index) => {
item.checked = true
})
}
}
})
})
document.addEventListener('keydown', (e) => {
shift = e.key
g = false
})
document.addEventListener('keyup', () => {
shift = null;
g = true
indexEnd = null
})
分析:
-
整体思路: 监听键盘Shift事件,以第一次点击的元素为起始,以按下shift后最后一次点击的元素为终止,将通过slice原数组将他们放置在一个数组中,并将它们所对应的checkbox变为true
-
具体实现:
- 首先通过querySelectorAll选定需要监听和修改的元素
- 为每个元素添加change事件并添加shift锁,即当按下shift后,锁住上一次点击的元素作为起始元素
- 当shift锁启动的时候,获取最后一次点击的元素,并且通过slice以start和end的下标为值,将他们所包含的元素放置在数组中,并为其添加选中属性
- slice的开始值不能大于结束值,为了实现反向多选效果,需要进行一次判断反转起始值
- 通过 input:checked选择器给被添加checked属性的元素添加样式
- 松开键盘后,重置shift锁
-
弊端分析(与官方方法对比):
- 监听了三次事件,过于冗余
- 大量使用了if条件和数组方法,有性能开销
- keyup监听了所有键盘抬起事件,可能会产生bug
- 定义了较多的全局变量,不利于后期维护
官方代码
官方代码仅代表该案例原作者思路,不唯一
结构
input:checked + p {
background: #F9F9F9;
text-decoration: line-through;
}
<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>
逻辑
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));
分析
仅代表本人对该代码的分析
建议直接去看Soyaine的中文详解
-
整体思路: 选中的第一个元素同时作为最后一个元素,当按下shift选中另一个元素的时候,进入forEach循环,该循环从数组的第一个元素开始,那么就必定会经过lastChecked所对应的元素,此时inBetween为true,直到遇到按下shift之后选中的元素
-
具体实现:
- handleCheck:遍历所有复选框,对于每个复选框,它会检查是否处于当前点击的复选框和上次点击的复选框之间,这个逻辑由 inBetween 变量控制,当遇到当前点击的复选框或上次点击的复选框时,inBetween 的值会取反,表示开始选中范围内的复选框。如果复选框处于选中范围内(inBetween 为真),那么就将它选中。此外,每次点击复选框时,lastChecked 变量会被更新为当前点击的复选框,以便下次点击时可以确定选中范围。
- 为所有checkbox注册事件,并执行函数
-
优点:
- 简洁易懂: 通过使用 Shift 键实现批量选择,用户可以轻松理解并快速掌握这种交互方式,而不需要额外的说明或复杂的用户界面。
- 高效实现: 使用 JavaScript 代码实现批量选择功能,能够通过简短的代码实现所需功能,提高了开发效率和代码的可维护性。
- 用户友好: 用户可以通过按住 Shift 键并选择起始复选框和目标复选框,来快速选择它们之间的所有复选框,提高了用户体验和操作效率。
- 可扩展性: 这种写法可以轻松地应用于不同数量的复选框,而不需要修改太多代码。因此,它具有一定的可扩展性,适用于各种规模的应用场景。