JavaScript 编码原则 | 青训营笔记

62 阅读4分钟

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

JavaScript 编码原则

1、各司其职

让HTML、CSS 和 JavaScript 职能分离

例:夜间模式切换

效果图.png

方案一:直接使用js操作样式

// HTML: 略
// CSS: 略
// JavaScript:
const btn = document.getELmentById('modeBtn')
btn.addEventListener('click', (e)=> {
    const body = document.body
    if(e.targe.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: 略
// JavaScript:
const btn = document.getElementById('modeBtn')
btn.addEventListener('click', (e) => {
    const body = document.body
    if(body.className !== 'night') {
        body.className = 'night'
    } else {
        body.className = ''
    }
})

这种方法相比方案一就显得较为直观,还可以更方便的编写各种复杂的样式。

但是可以发现这个功能只是存粹的样式,那么是否可以只用css完成这个效果?

方案三:只使用CSS完成效果

// HTML:
<input id="modeCheckBox" type="checkbox">
<div class="content">
    <header>
        <label id="modeBtn" for="modeCheckBox" />
        <h1>深夜食堂</h1>
    </header>
    <main>
        ...
    </main>
</div>

// CSS:
...
#modeCheckBox {
    display: none;
}

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

这种方案中使用到了checkbox和label。将checkbox隐藏,再通过labal的for属性关联checkbox。 css中使用了伪类选择器,当checkbox选中时修改其兄弟节点的样式。

总结

通过上面的例子应该可以体会到“各司其职”的含义和效果,可以得出结论:

  • HTML/CSS各司其职
  • 应当避免不必要的由JS直接操作样式
  • 可以用class来表示状态
  • 纯展示的交互可以寻求零JS方案

2、组件封装

组件是指Web页面上抽出来的一个个包含模板(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、拓展性、复用性。

例:轮播图组件

实现流程

1、定义HTML结构

轮播图是一个列表结构,可以用ul来实现轮播图的结构

2、实现CSS样式

首先消除ul的默认样式,然后通过绝对定位将轮播图的图片重叠到一起,最后通过控制透明度控制是否展示

3、实现JS行为

  • Slide
    • getSelectedItem()
    • getSelectedItemIndex()
    • slideTo()
    • slideNext()
    • slidePrevious()

这种实现方案虽然可以实现轮播图的功能,但是这样使得这个组件的各个部分是联系在一起的,如果想要修改轮播图组件的某一部分就得修改HTML、CSS和JS。因此可以将组件的各个功能进行解耦

优化一: 插件化

1、目的:

  • 将控制元素抽取成插件
  • 插件与组件之间通过依赖注入的方式建立联系

2、做法: 实现一个注入方法并将各种控制元素的功能抽离出来,通过注入方法与轮播图组件建立联系并控制组件

3、效果: 这样的话如果要增加控制元素只需要实现控制功能后将该控制插件注入轮播图组件即可

image.png

4、不足:这种方案虽然进行了插件化,但是如果要增加或删除某个插件还是需要对HTML和CSS进行修改

优化二:模板化

1、目的:将HTML模板化,实现数据驱动

image.png 2、做法:添加render方法,通过传入的数据渲染HTML页面 3、效果:要增加或删除某个插件只需要修改JS即可。

image.png

但这还不是优化的终点,还可以将组件通用模型抽象出来

优化三:抽象化

将轮播图组件抽象为通用组件

image.png

总结

  • 组件设计原则:封装性、正确性、扩展性、复用性
  • 实现组件的步骤:结构设计、样式设计、行为设计、优化设计
  • 优化方法:
    • 插件化
    • 模板化
    • 抽象化

上面的优化仍有很大的改进空间。比如说组件与插件之间是分离的,这样虽然简单,但是没有考虑父子组件。还有就是上面只进行了HTML的模板化,并未对CSS进行模板化。

注意: 虽然将HTML和JS进行抽象,但是并未违反各司其责的原则。因为各司其责指的是各自负责各自的职能。虽然将HTML和JS抽象到一起,但是它们仍然负责自己的职能。

3、过程抽象

用来处理局部细节控制的一些方法,是函数式编程的基础应用。将函数本身看成是一个封装好的过程,关注输入和输出。但并不是所有的函数都是无副作用的输入和输出,只有纯函数(不改变外界环境)是。

image.png