这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天. 会写前端项目不难,但是成为一名专业的前端工程师,路漫漫。
如何写好JavaScript?
很多同学选择了前端,是因为前端的入门门槛并不高,学习了三件套之后基本的前端网页都能实现,然而代码的质量堪忧。而真正的专业前端工程师的代码却尤其简洁,可读性强,即是按照Javascript的编码标准原则。
这篇笔记是跟随着工作十余年的前端大佬月影老师来学习如何写出最美的JS代码。
Javascript的编码标准原则。
- 各司其职 - 让HTML、CSS和JavaScript职能分离。
- 组件封装 - 好的UI组件具备正确性、扩展性、复用性。
- 过程抽象 - 应用函数式编程思想。
各司其职
- 让HTML、CSS和JavaScript职能分离。
示例:
写一段JS,控制一个网页,让它支持浅色和深色两种浏览模式。
基础版本一:
思路:通过点击事件,如果点击的目标html内容为阳光,我们让body.style.backgroundColor = 'black', 字体改为白色,并且将目标html内容改为月亮。
const btn = document.getElementById("btn");
const body = document.body;
btn.addEventListener('click',(e) => {
if(e.target.innerHTML=="sun"){
body.style.backgroundColor = 'black';
body.style.color = 'white';
e.target.innerHTML = "black"
}else{
body.style.backgroundColor = 'white';
body.style.color = 'black';
e.target.innerHTML = "sun"
}
})
版本二:
const btn = document.getElementById("btn");
const body = document.body;
btn.addEventListener('click',(e) => {
if(body.className!==‘night’){
body.className = 'night';
}else{
body.className = '';
}
})
并且在css中添加夜晚样式,为了更丝滑,添加transition
body.night {
background-color:black;
color:white;
transition: all 1s;
}
#btn::after {
content: 'sun';
}
body.night #btn::after{
content: 'night'
}
前两个版本区别:
版本一直接通过dom来操作节点的css样式,而JS来完成css的需求。
并且从维护而言,代码的可读性应该是很强的,版本一也不易于后期开发人员阅读,并且又臭又长。
相对而言,版本二更加简洁易读,将夜晚的样式写在单独的css里,而JS只需要通过改变className即可。
缺点:
这个版本虽然简洁,但是本质上还是通过click切换,控制样式来实现。但是一般而言,控制样式是可以通过纯CSS来实现。根据各司其职的原则,CSS应当遵循控制样式的职责。
版本三:
然而,前两个版本一直在通过JS来实现,是否能完全使用CSS来实现这个需求呢?修改样式本就是CSS的职责所在,那么通过CSS来实现即是最佳方案。
思路:通过checkbox的方式来实现,将网页的所有内容放在checkbox下面的一个div里,当checkbox打勾时,变夜晚,当checkbox不打勾时,恢复白天。
其次,隐藏checkbox,并且通过label标签的for属性,可以指定"sun"继承checkbox,因此它被选中时,就变成黑夜,不选中即回到白天。
#ccheckbox:checked + .content {
background-color:black;
color:white;
transition: all 1s;
}
#btn::after {
content:'sun';
}
#ccheckbox:checked + .content #btn::after {
content: 'night';
}
总结
- HTML/CSS/JS各司其责
- 应当避免没必要的由JS直接操作样式
- 可以用class来表示状态
- 统展示类交互寻求零JS方案
组件封装
‘‘组件是 Web 页面上所抽取的模版、功能与样式的单元,自从 React,Vue 等前端框架在市面上大量使用之后,组件化开发逐渐成为了前端主流开发方式。’’
组件是指Web页面上抽出来一个个包含模板(HTML)、功能(JS)和样式(CSS)的单元。好的UI组件具备正确性、扩展性、复用性。
依旧通过一个示例:
用原生JS写一个轮播图的组件。那么分三部分:模板(HTML)、功能(JS)和样式(CSS)
结构设计:HTML
轮播图是一个典型的列表结构,即从上往下几张图,可通过无序列表ul元素来实现
表现:CSS
- CSS则是通过绝对定位将图片重叠在同一个位置上
- 轮播图切换的状态使用修饰符
- 为了效果更丝滑,使用切换动画
transition
行为:JS
API设计:通过构造函数,构造一个类Slider,将方法写进类里。
Event(控制流):使用自定义事件来解耦。
然而,当我们要改变组件时,却十分困难,因为所有的API都已经定义好在一起,很不好操作。
改进:1. JS插件化:将控制元素抽取成插件,那么在后期想取消哪个插件时,只要注销掉某个插件即可,也不会影响到整体,插件与组件之间通过依赖注入方式建立联系
- 进一步优化,模板化(HTML),将HTML模板化,更易于扩展。JS的UI组件里需要做到数据驱动,根据数据生成HTML模板,比如当图片数量发生改变时。通过手写JS的render方法来生成。
class Slider{
constructor(id, opts = {images:[], cycle: 3000}){
this.container = document.getElementById(id);
this.options = opts;
this.container.innerHTML = this.render();
this.items = this.container.querySelectorAll('.slider-list__item, .slider-list__item--selected');
this.cycle = opts.cycle || 3000;
this.slideTo(0);
}
render(){
const images = this.options.images;
const content = images.map(image => `
<li class="slider-list__item">
<img src="${image}"/>
</li>
`.trim());
return `<ul>${content.join('')}</ul>`;
}
- 最终优化:抽象。将组件通用模型抽象出来。
总结
-
组件设计的原则:封装性、正确性、扩展性、复用性
-
实现组件的步骤:结构设计、展现效果、行为设计
-
三次重构
- 插件化
- 模板化
- 抽象化(组件框架)
过程抽象
应用函数式编程思想。
组件封装主要侧重于整体的UI组件,而这部分则是注重局部细节控制的方法,以及函数式编程思想。