这是我参加「第四届青训营 」笔记创作活动的第三天。
今天跟着月影大佬学习了一些有关JavaScript的内容,那么接下来看看有哪些需要注意的点吧。
1. 写好JS的一些原则
- 各司其职:让HTML、CSS和JavaScript职能分离
- 组件封装:好的UI组件具备正确性扩展性、复用性
- 过程抽象:用函数式编程思想
2. 具体应用
2.1 各司其职:深色/浅色模式
当一个页面需要深色和浅色浏览模式,用JS应当如何实现?
2.1.1 my idea
在css代码中写好浅色和深色的样式,类名分别为white、black,在JS中当鼠标点击切换模式的按钮时,获取当前浏览模式的类名,如果当前为white,且切换为black,反之。
const btn = document.getElementById('modeBtn');
btn.addEventListener('click', (e) => {
const body = document.body;
if(body.className !== 'black') {
body.className = 'black';
} else {
body.className = 'white';
}
});
PS :还可直接在js代码中直接修改body.style.color等属性,但在上面所提到的原则中,这样没有各司其职,JS代码直接操作了CSS,应切换状态即可。
2.1.2 大佬优化方案
纯用CSS和HTML,无JS,用 运用CSS的高级功能,使用伪类选择器匹配元素状态。给checkbox设置checked状态,然后设置样式。在lable上用for属性,for的值为checkbox的id,此时点击lable和点击checkbox的作用一样,则切换状态。
<input id="modeCheckBox" type="checkbox">
<div class="content">
<header>
<label id="modeBtn" for="modeCheckBox"></label>
<h1>深夜食堂</h1>
</header>
<main>
<div class="pic">
<img src="https://p2.ssl.qhimg.com/t0120cc20854dc91c1e.jpg">
</div>
<div class="description">
<p>
这是一间营业时间从午夜十二点到早上七点的特殊食堂。这里的老板,不太爱说话,却总叫人吃得热泪盈
</p>
</div>
</main>
</div>
#modeCheckBox {
display: none;
}
#modeCheckBox:checked + .content {
background-color: black;
color: white;
transition: all 1s;
}
2.1.3 小结
- HTML/CS/JS各司其职
- 避免不必要的由JS直接操作样式
- 可以用class来表示状态
- 纯展示类交互寻求零JS方案
2.2 组件封装:原生JS写一个轮播图网站
组件是指Web页面抽取出来一个个包含模板、功能、样式的单元。好的组件具备封装性、正确性、扩展性、复用性。
2.2.1 my idea
html使用img标签,css使用@keyframes动画,让图片逐渐移动, js代码中使用定时器让图片到时间就切换,修改img中的src。
2.2.2 大佬优化方案1
- HTML 轮播图是典型的列表结构,可以使用无序列表ul元素来实现。
<div id="my-slider" class="slider-list">
<ul>
<li class="slider-list__item--selected">
<img src="https://p5.ssl.qhimg.com/t0119c74624763dd070.png">
</li>
<li class="slider-list__item">
<img src="https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg">
</li>
<li class="slider-list__item">
<img src="https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg">
</li>
<li class="slider-list__item">
<img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg">
</li>
</ul>
</div>
- CSS
- 使用CSS绝对定位将图片重叠放在同一个位置
- 轮播图切换的使用状态使用修饰符
- 轮播与的切换动画使用CSS transition
#my-slider{
position: relative;
width: 790px;
}
.slider-list ul{
list-style-type:none;
position: relative;
padding: 0;
margin: 0;
}
.slider-list__item,
.slider-list__item--selected{
position: absolute;
transition: opacity 1s;
opacity: 0;
text-align: center;
}
.slider-list__item--selected{
transition: opacity 1s;
opacity: 1;
}
- JS
使用API
- getSelectedltem( )得到当前选中的图片元素
- getSelectedltemIndex( )得到当前选中的图片元素在列表中的下标
- slideTo( )到特定元素上
- slideNext( )向下轮播
- slidePrevious( )向上轮播 定义Slider类,定义以上API
class Slider{
constructor(id){
this.container = document.getElementById(id);
this.items = this.container
.querySelectorAll('.slider-list__item, .slider-list__item--selected');
}
getSelectedItem(){
const selected = this.container
.querySelector('.slider-list__item--selected');
return selected
}
getSelectedItemIndex(){
return Array.from(this.items).indexOf(this.getSelectedItem());
}
slideTo(idx){
const selected = this.getSelectedItem();
if(selected){
selected.className = 'slider-list__item';
}
const item = this.items[idx];
if(item){
item.className = 'slider-list__item--selected';
}
}
slideNext(){
const currentIdx = this.getSelectedItemIndex();
const nextIdx = (currentIdx + 1) % this.items.length;
this.slideTo(nextIdx);
}
slidePrevious(){
const currentIdx = this.getSelectedItemIndex();
const previousIdx = (this.items.length + currentIdx - 1)
% this.items.length;
this.slideTo(previousIdx);
}
}
const slider = new Slider('my-slider');
slider.slideTo(3);
控制流
<a class="slide-list__next"></a>
<a class="slide-list__previous"></a>
<div class="slide-list__control">
<span class="slide-list__control-buttons--selected"></span>
<span class="slide-list__control-buttons"></span>
<span class="slide-list__control-buttons"></span>
<span class="slide-list__control-buttons"></span>
</div>
const detail = {index: idx}
const event = new CustomEvent('slide', {bubbles:true, detail})
this.container.dispatchEvent(event)
2.2.3 小结
- 组件设计原则:封装性、正确性、扩展性、复用性
- 实现组件步骤:结构设计,展现效果,行为设计(API功能、Event控制流)
- 三次重构:插件化、模板化、抽象化 (可将控制元素抽取成插件,插件与组件之间通过依赖注入方式建立连接,将HTML模块化)
2.3 过程抽象:操作次数限制
用来处理局部细节控制的一些方法,函数式编程思想的基础应用
2.3.1 my idea
用变量值count,初始值为0,每操作一次,count加一,并进行判断是否超过限定值。
2.3.2 大佬优化
使用高阶函数来实现过程抽象,高阶函数是以函数作为返回值和参数,常用作于函数装饰器。
function HOF0(fn) {
return function(...args) {
return fn.apply(this, args);
}
}
常用高阶函数:Once、Throttle、Debounce、Consumer/2、Iterative 操作次数限制则可使用Once
2.3.3 为什么使用高阶函数
可以提高可维护性
总结
今天讲了很多案例,在实际开发中能够运用,但我基础稍微薄弱,还应多加了解,并掌握一些基本算法。