【青训营】写好JS——各司其责

192 阅读2分钟

这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战

业精于勤,荒于嬉;行成于思,毁于随。

各司其责:各自负责掌握自己的职责。

image.gif

我们要明白:把CSS,JS放到单文件中这种代码层面的分离并不是各司其责,各司其责要做到职责的分离,比如我们要尽可能避免JS直接操作样式。

例子:Dark Mode

用JS实现浅色模式和深色模式的切换,如果是你,你会怎么做?

学成归来版

学完月影大大的JS课,复刻了一个常见的Dark Mode切换方式当作业,想看代码可以点这里,如果想知道怎么做,就继续往下看吧!

darkgif

第一版

我们先写一段示例用的HTML:

image-20220123202438302

新手可能会这样写JS来切换模式:

const btn = document.getElementById('modeBtn');
const body = document.body;

btn.addEventListener('click', (e) => {
  if(e.target.innerHTML === '🌞') {
    body.style.backgroundColor = 'black';
    body.style.color = 'white';
    e.target.innerHTML = '🌜';
  } else {
    body.style.backgroundColor = 'white';
    body.style.color = 'black';
    e.target.innerHTML = '🌞';
  }
});

这样写看似逻辑很清晰,但是JS代码直接操作了HTML和CSS,显然没有做到各司其责,而且代码可读性不是很好,第一时间并不能让人分辨出这是切换深色模式的代码。

第二版

第二版我们先在CSS里封装一个深色类,通过::after伪类添加HTML内容:

.night {
  background-color: black;
  color: white;
  transition: all 1s;
}

#modeBtn::after {
  content: '🌞';
}

.night #modeBtn::after {
  content: '🌜';
}

然后JS只用添加或者删除类名就可以实现样式切换,这也是我常用的方法:

const btn = document.getElementById('modeBtn');

btn.addEventListener('click', (e) => {
  const body = document.body;
  if (body.className !== 'night') {
    body.className = 'night';
  } else {
    body.className = '';
  }
});

也可以用toggle()简化一下,关于该函数的用法可以看MDN文档

const btn = document.getElementById("modeBtn");

btn.addEventListener("click", (e) => {
  document.body.classList.toggle("night");
});

这样写没有直接操作页面样式,JS只需要修改元素的类名即可,同时类名night又能让人很容易分辨出代码的用途,但这就是最好的解决方案了吗?月影大大告诉你,并没有,我们还有最终版!

最终版

只要我不写代码,就永远不会有Bug!

我们先来思考一个问题,既然我们只是单纯的展示页面,我们能不能不用JS呢?单纯的CSS能不能实现这个切换功能呢?答案是当然可以。

CSS中checkbox复选框就有checked选中和未选中两种状态,正好可以用来实现状态的切换。我们把复选框隐藏,然后用label显示🌞🌜:

<input id="modeCheckBox" type="checkbox">
<div class="content">
  ...
  <label id="modeBtn" for="modeCheckBox"></label>
  ...
  
</div>


<style>
	#modeCheckBox {
  	display: none;
  }

  #modeCheckBox:checked + .content {
    background-color: black;
    color: white;
    transition: all 1s;
  }

  #modeBtn::after {
    content: '🌞';
  }
  
  #modeCheckBox:checked + .content #modeBtn::after {
  	content: '🌜';
	}
</style>

重剑无锋,大巧不工。我们应该做到:

  1. HTML/CSS/JS 各司其责
  2. 避免不必要的由JS直接操作样式
  3. 用class来表示状态
  4. 纯展示类的页面交互寻求零JS方案