30天JS挑战(第十天)

84 阅读4分钟

第十天挑战(计划便签)

地址:javascript30.com/

所有内容均上传至gitee,答案不唯一,仅代表本人思路

中文详解:github.com/soyaine/Jav…

该详解是Soyaine及其团队整理编撰的,是对源代码的详解强烈推荐大家观看学习!!!!!!!

本人gitee:gitee.com/thats-all-r…

效果

image.png

  • 样式分析

    • 组件整体居中
    • 组件左侧为复选框,右侧为该复选框对应的计划
    • 复选框被选中时,有划线效果,文字背景加深
  • 逻辑分析

    • 当复选框被选中后,其对应的事项会被添加样式
    • 按住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 键并选择起始复选框和目标复选框,来快速选择它们之间的所有复选框,提高了用户体验和操作效率。
    • 可扩展性: 这种写法可以轻松地应用于不同数量的复选框,而不需要修改太多代码。因此,它具有一定的可扩展性,适用于各种规模的应用场景。