写好JS的三大原则之「各司其责」|青训营笔记

787 阅读5分钟

这是我参与「第四届青训营 」笔记创作活动的的第4天

写好JS的三大原则之「各司其责」

大家好,这里是昨天晚上想到自己写的垃圾文档没睡好决定重写文档的Vic,昨天已经发过这篇文章了,但是个人觉得写的太差了,单纯的复制代码简直是bullshit。因此,今天决定重写这篇文章。

00590E08.jpg

在这篇文章中同样采用模式切换的例子作为讲解,不同的是,我将带大家从头到尾慢慢捋一遍各司其责原则。

什么是各司其责

首先我们来讲解一下,什么是各司其责原则。众所周知,我们的网页由三部分构成--HTML、CSS、JS,这三部分分别对应着网页的结构、样式、行为。因此,当我们在开发中需要对网页的某个部分查看时,只需要对对应的文件查看即可。为了方便这种查看,我们引入各司其责原则。

简单的来说,各司其责就是让HTML、CSS和JS的职能分离,各自只负责自己该负责的部分。

在没有各司其责原则下的模式切换实现

新手开发者在JS的开发过程中往往忘记各司其责原则,因此,在这里,我们以新手的思路写一个模式切换实现过程。

首先进行HTML部分的实现,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>模式切换新手思路</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
    <button id="modeBtn">🌞</button>
    <h3>这是一个模式切换的案例</h3>
  </header>
  <main>
    <p>大家好,我是Vic。</p>
    <br />
    <p>请在写JS的时候遵循各司其责原则。</p>
  </main>
  <script src="./index.js"></script>
</body>
</html>

接下来进行CSS的编写:

body,
html {
  width: 100%;
  height: 100%;
  max-width: 600px;
  padding: 0;
  margin: 0;
  overflow: hidden;
}
body {
  padding: 10px;
  box-sizing: border-box;
  transition: all 1s;
}
#modeBtn {
  float: right;
  border: none;
  outline: none;
  cursor: pointer;
  font-size: 2rem;
  background-color: inherit;
}

下面是最为关键的JS部分的编写,在这里由于不考虑各司其责原则,我们使用JS操作文档中的DOM。其代码如下:

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

modeBtn.addEventListener('click', (e) => {
  const body = document.body;
  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 = '🌞';
  }
})

这段代码还是很容易理解的,因此在这里我们并不对代码内容进行讲解。代码的效果如下:

模式切换新手.gif

有的同学可能就会想了,对啊,没错啊,我把功能实现了,效果还挺好的,代码也有很好的易读性。但是,在实际开发中,我们往往写的代码结构并不会像现在这样简短,因此,当我们采用这种方式进行操作的时候,返回来阅读代码时,我们阅读代码的难度就大大增加了。作为代码的编写者,我们可能会比较轻松地了解代码段的含义,然而当参与的人员多的情况下,代码还会很容易被其他参与者阅读吗?

答案是否定的,因此,我们需要使用各司其责原则。接下来,我们引入各司其责原则进行代码的编写。

各司其责原则下的模式切换实现

首先上代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>模式切换新手思路</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <header>
    <button id="modeBtn"></button>
    <h3>这是一个模式切换的案例</h3>
  </header>
  <main>
    <p>大家好,我是Vic。</p>
    <br />
    <p>请在写JS的时候遵循各司其责原则。</p>
  </main>
  <script src="./index.js"></script>
</body>
</html>
body,
html {
  width: 100%;
  height: 100%;
  max-width: 600px;
  padding: 0;
  margin: 0;
  overflow: hidden;
}
body {
  padding: 10px;
  box-sizing: border-box;
  transition: all 1s;
}
body.night {
  background-color: black;
  color: white;
  transition: all 1s;
}
#modeBtn {
  float: right;
  border: none;
  outline: none;
  cursor: pointer;
  font-size: 2rem;
  background-color: inherit;
}
#modeBtn::after {
  content: '🌞';
}
body.night #modeBtn::after {
  content: '🌛';
}

HTML部分的代码和之前基本上没有什么区别,唯一的区别是,在这里我们采用将按钮中的内容作为CSS的样式,在CSS中进行编写。

有的同学可能不太明白这个操作,在这里建议补充一下伪元素的相关知识

我们可以看到在CSS中,我们给body元素编写了一个night类名下的样式,所以不难想到,在JS中,我们采用更改类名的方法来进行样式的变换。JS部分的代码如下:

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

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

这就完成了一个各司其责的模式切换版本,在实际的开发中,当另外的开发者接手我们的项目的时候就可以很直观的了解到我们这段JS代码所要实现的功能了。

那么,还有没有更加厉害的方案呢?月影老师给我们带来了模式切换的终极版本。

模式切换终极版本

武侠小说中常常有“无招胜有招”的说法,所谓不战而屈人之兵,最好的战就是不站。化用到我们这里,那么最好的JS就是不用写JS。

这是为什么呢?因为在我们的需求中只需要实现样式的切换即可,它是一个纯展示类交互。且存在两个状态,因此,我们可以使用一个CheckBox,通过其勾选状态来进行模式的切换。代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>模式切换新手思路</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <input type="checkbox" name="modeChange" id="modeChange" />
  <div class="content">
    <header>
      <label for="modeChange" id="modeBtn"></label>
      <h3>这是一个模式切换的案例</h3>
    </header>
    <main>
      <p>大家好,我是Vic。</p>
      <br />
      <p>请在写JS的时候遵循各司其责原则。</p>
    </main>   
  </div>

  <!-- <script src="./index.js"></script> -->
</body>
</html>
body,
html {
  width: 100%;
  height: 100%;
  max-width: 600px;
  padding: 0;
  margin: 0;
  overflow: hidden;
}
body {
  padding: 10px;
  box-sizing: border-box;
  transition: all 1s;
}
#modeChange {
  display: none;
}
#modeChange:checked + .content {
  background-color: black;
  color: white;
  transition: all 1s;
}
#modeBtn {
  float: right;
  border: none;
  outline: none;
  cursor: pointer;
  font-size: 2rem;
  background-color: inherit;
}
#modeBtn::after {
  content: '🌞';
}
#modeChange:checked + #modeBtn::after {
  content: '🌛';
}

总结

在实际的开发中,我们需要牢记各司其责的原则,尽量避免使用JS直接对样式进行操作,而转为使用class进行状态的表示。

最后写一点我个人的看法,我认为在实际的开发工作中,我们只需要做到第二个版本的程度就可以了。在完成功能的基础上,可以在进行进一步的零JS方案。

写在最后

今天早上起来看昨天写的文档真的是看一次吐一次,也不准备将那个文档删掉了,作为一个警惕教训吧。

毕竟说实话,如果没有多少自己的思考、自己的实践,那写文档干嘛呢。简单的CV操作不如直接贴链接了。