如何写好 JS | 青训营笔记

133 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天

各司其职

原生 JS 实现一个切换深色模式的功能,我们会怎么做?我们或许使用 JS 来调整 CSS 变量来实现:

const btn = document.getElementById('modeBtn')
btn.addEventListener('click', (e) => {
    const body = document.body;
    if (e.target.innerText === '深色模式') {
        body.style.setProperty('--bg-color', '#000')
        body.style.setProperty('--text-color', '#fff')
        e.target.innerText = '浅色模式'
    } else {
        body.style.setProperty('--bg-color', '#fff')
        body.style.setProperty('--text-color', '#000')
        e.target.innerText = '深色模式'
    }
})

但是实际上,这样的代码是不够优雅的,因为我们的 JS 代码和 CSS 代码耦合在了一起,如果我们想要修改 CSS 样式,我们就需要修改 JS 代码,这样的代码不利于维护。我们可以用类名来控制样式,这样的代码就会更加优雅:

const btn = document.getElementById('modeBtn')

btn.addEventListener('click', (e) => {
    const body = document.body;
    if (e.target.innerText === '深色模式') {
        body.classList.add('dark')
        e.target.innerText = '浅色模式'
    } else {
        body.classList.remove('dark')
        e.target.innerText = '深色模式'
    }
})

这就是各司其职的原则,我们的 JS 代码只负责控制逻辑,而不负责样式,样式的控制交给 CSS 来做,这样的代码更加优雅,也更加容易维护。

具体例子

修改前:

 <header>
    <button id="modeBtn">🌞</button>
    <h1>深浅色模式切换</h1>
 </header>
 
 body,
    html {
      width: 100%;
      height: 100%;
      padding: 0;
      margin: 0;
      overflow: hidden;
    }

    body {
      padding: 10px;
      box-sizing: border-box;
    }

    #modeBtn {
      font-size: 2rem;
      float: right;
      border: none;
      background: transparent;
    }

window.onload=function(){
    document.getElementById("file-btn") 
    const btn = document.getElementById('modeBtn');

    btn.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 = '🌞';
      }
    });
}

修改后:

//html
 <header>
        <button id="modeBtn"></button>
        <h1>深浅色模式切换</h1>
 </header>
 
 //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 {
      font-size: 2rem;
      float: right;
      border: none;
      outline: none;
      cursor: pointer;
      background: inherit;
    }

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

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

    body.night #modeBtn::after {
      content: '🌜';
    }
    
//js
window.onload=function(){
    document.getElementById("file-btn") 
   const btn = document.getElementById('modeBtn');
        btn.addEventListener('click', (e) => {
        const body = document.body;
        if (body.className !== 'night') { 
            //通过className的'night'来显示深色模式
            body.className = 'night';
        } else {
            body.className = '';
        }
        });
}

组件封装

组件封装是指将一个功能封装成一个组件,这个组件可以被复用,这样的代码更加优雅,也更加容易维护。常见的组件封装有:

  • 轮播图,可以复用在首页、详情页等
  • 搜索框,可以复用在首页、详情页等
  • 评论组件,可以复用在首页、详情页等
  • 登录组件,可以复用在首页、详情页等
  • 深色模式切换组件,可以复用在首页、详情页等

组件封装有下面的基本方法:

  • 结构设计
  • 展示效果
  • 行为设计(API、Event)

使组件具备封装性、正确性、扩展性、复用性。

过程抽象

过程抽象是指将用来处理局部细节控制的代码封装成一个函数,以函数式的编程思想来编写代码。

在过程抽象中,我们需要注意的是:

  • 函数的功能单一
  • 函数的参数尽量少
  • 函数的返回值尽量少

扩展:Leftpad 事件

在 2016 年,npm 上有一个名为 left-pad 的包,这个包的作用是在字符串前面补全空格,比如:

leftPad('hello', 10) // '     hello'

这个包的作者在 2016 年 4 月 1 日发布了 1.0.0 版本,但是在 2016 年 4 月 2 日,这个包的作者删除了这个包,这个事件被称为 Leftpad 事件。这个模块下架导致了很多依赖这个模块的项目无法正常运行。实际上,这个代码只有 11 行,而且这个代码也不是很复杂,但是却很多人使用,完全可以自己写一个。

这给我们的启示是:

  • 不要过度依赖第三方库
  • 对自己的代码负责