这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
月影老师告诉我们写好JavaScript(包括其他语言)的三大原则 ① 各司其责 ② 组件封装 ③ 过程抽象
1.什么是各司其责
众所周知,我们的网页由三部分构成--HTML、CSS、JS,这三部分分别对应着网页的结构、样式、行为。因此,当我们在开发中需要对网页的某个部分查看时,只需要对对应的文件查看即可。为了方便这种查看,我们引入各司其责原则。
简单的来说,各司其责就是让HTML、CSS和JS的职能分离,各自只负责自己该负责的部分。 接下来拿暗夜模式来举例说明
2. 深色模式
现在很多网页都支持浅色模式和深色模式的切换,那用 JavaScript 应该怎么实现呢?
新手版
首先我们来看看页面的结构 HTML
<header>
<button id="modeBtn">🌞</button>
</header>
<main>
<div class="pic">
<img src="./1.png">
</div>
<div class="description">
<p>
文章内容....
</p>
</div>
</main>
然后我们来看看我们页面的样式 CSS
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;
}
最后我们来看看我们页面的行为JavaScript
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 = '🌞';
}
});
我们来看看上面这段JavaScript代码的逻辑
- 获取切换按钮元素
- 给按钮绑定鼠标点击事件
- 获取页面body元素
- 判断当前按钮元素是🌞还是🌜
- 是🌞就将页面的背景色改成黑色,字体颜色改成白色,并将按钮元素变成🌜
- 否则说明按钮就是🌜,我们就将页面背景色改为白色,字体改为黑色,并将按钮元素变成🌞
作为前端新人的我,觉得这段代码还不错的~ 逻辑很清晰,功能也可以
但是 这段代码违背了我们各司其责这个原则的!
这里的JavaScript代码,既修改了元素的样式,也修改了元素的结构!!! 你不会想象到这段JavaScript的含义是完成网页深色与浅色模式的切换这样一个功能的!
还有就是如果让你把深色模式中的字体颜色换成别的颜色,是不是还要修改JS代码来操作呢?方便给黑白模式加上一些过渡效果吗?
所以说新手版的代码,不够好!可以进行优化
新手优化版
可以通过用css给元素添加一些类的样式,让JavaScript修改他们的类名就可以了~就实现了 样式与行为分离了
先来看看页面的结构
<header>
<button id="modeBtn"></button>
</header>
<main>
<div class="pic">
<img src="./1.png">
</div>
<div class="description">
<p>
文章内容....
</p>
</div>
</main>
除了按钮那里的🌞删去了,其他都是没有变化的
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: '🌜';
}
- 通过给button加after伪元素,提供🌞与🌜的内容,这样就不用JS来修改页面的结构了
- 通过设定night类名,让页面背景变黑字体颜色变白,实现黑色模式,并且加入过渡效果
- 这样元素就可以通过设置不同的类名展示不同的样式了
JavaScript
const btn = document.getElementById('modeBtn');
btn.addEventListener('click', (e) => {
const body = document.body;
if (body.className !== 'night') {
body.className = 'night';
} else {
body.className = '';
}
});
仅仅是修改元素的类名className,没有直接操作页面的样式,可读性也得到了很大的提升。
还加入了过渡的效果transition: all 1s;
,使得用户体验更好!拓展性更高,如果要更改需求,比如要改变字体的颜色之类的,只需要改动CSS中的代码即可~
这里其实做的已经不错了~但是还有没更好的解决方案呢?
大师版
如何写出没有bug的JS,那就是不写JS!!!
页面结构HTML
<input id="modeCheckBox" type="checkbox">
<div class="content">
<header>
<label id="modeBtn" for="modeCheckBox"></label>
</header>
<main>
<div class="pic">
<img src="./1.png">
</div>
<div class="description">
<p>
文章内容...
</p>
</div>
</main>
</div>
首先用一个大盒子将我们要显示的内容包裹起来,然后通过label元素代替之前的button元素,将它指向大盒子外面的checkbox元素
CSS
body,
html {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
}
body {
box-sizing: border-box;
}
.content {
padding: 10px;
transition: background-color 1s, color 1s;
}
#modeCheckBox {
display: none;
}
#modeCheckBox:checked+.content {
background-color: black;
color: white;
transition: all 1s;
}
#modeBtn {
font-size: 2rem;
float: right;
}
#modeBtn::after {
content: '🌞';
}
#modeCheckBox:checked+.content #modeBtn::after {
content: '🌜';
}
分析一下
- 由于HTML的结构,点击label就相当于点击了checkbox【为什么要用checkbox呢,因为他可以通过点击,记住用户的状态,勾选和不勾选的两个状态,刚好对应我们的白色模式和深色模式两种状态】
- 将大盒子外面的checkbox隐藏起来
display: none;
(有label指向checkbox了) - 通过 checkbox 的伪类选择器checked,点击checkbox就会触发这个伪类
- 通过相邻兄弟选择器
+
选择到checkbox下面的大盒子 - 这样就可以实现在CSS控制元素点击后的样式切换了
3. 最佳实践
- HTML、CSS、JavaScript 各司其责
- 应当避免不必要的由JS 直接操作样式
- 可以用
class
来表示状态,类名具有不错的业务语义 - 纯展示类交互寻求零JavaScript方案