一、如何写好JavaScript?
推荐书籍:JavaScript(犀牛书)、JavaScript The Good Parts(语言精髓)
写好JS的一些原则
1.各司其职:让HTML、CSS和JavaScript 职能分离
HTML负责结构
CSS负责表现
JavaScript 负责行为
例如:如今有很多页面有深色和浅色模式,可以随机切换。实现这个可以单独使用HTML和CSS来编写,但是不便于阅读。
2.组件封装:好的UI组件具备正确性、扩展性、复用性
3.过程抽象:应用函数式编程思想
二、组件封装
组件是指Web网页上抽出来一个个包含模板(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。
例子:用原生JS写一个电商网站的轮播图,该怎么实现?
1.结构
轮播图是一个典型的列表结构,可以使用ul来实现
2.表现
- 使用CSS绝对定位将图片重叠在同一个位置
- 轮播图切换的状态使用修饰符(modifier)
- 轮播图的切换动画使用CSS transition
3.行为-控制流
- 使用自定义事件来解耦
class Slider {
constructor(id) {
this.container = document.getElementById(id);
this.items = this.container.querySelectorAll('.slider-list__item, .slider-lise__item--selected');
this.cycle = cycle;
const controller = this.querySelector('.slider-list__control');
if (controller) {
const buttons = controller.querySelectorAll('.slider-list__control-buttons, ..slider-list__control-buttons--selected');
controller.addEventListener('mouseover', evt => {
const idx = Array.from(buttons).indexOf(evt.target);
if (idx >= 0) {
this.sliderTo(idx);
this.stop();
}
});
controller.addEventListener('mouseout', evt => {
this.start();
});
this.container.addEventListener('slide', evt => {
const idx = evt.detail.index;
const selected = controller.querySelector('.slider-list__control-buttons--selected');
if (selected) selected.className = 'slider-list__control-buttons';
buttons[idx].className = 'slider-list__control-buttons--selected';
});
}
const previous = this.container.querySelector('.slide-list__previous');
if (previous) {
previous.addEventListener('click', evt => {
this.stop();
this.sliderPrevious();
this.start();
evt.preventDefault;
});
}
const previous = this.container.querySelector('.slide-list__next');
if (previous) {
previous.addEventListener('click', evt => {
this.stop();
this.sliderNext();
this.start();
evt.preventDefault;
});
}
}
getSelectedItem() {
const selected = this.container
.querySelector('.slider-list__item--selected');
return selected;
}
getSelectedItemIndex() {
return Array.from(this.items).indexOf(this.getSelectedItem());
}
sliderTo(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';
}
const detail = { index: idx }
const event = new CustomEvent('slide', { bubbles: true, detail })
this.container.dispatchEvent(event)
}
sliderNext(){
const currentIdx = this.getSelectedItemIndex();
const nextIdx = (currentIdx + 1) % this.items.length;
this.sliderTo(nextIdx);
}
sliderPrevious() {
const currentIdx = this.getSelectedItemIndex();
const previousIdx = ((this.items.length) + currentIdx - 1)
% this.items.length;
this.sliderTo(previousIdx);
}
start() {
this.stop();
this._timer = setInterval(() => this.sliderNext(), this.cycle);
}
stop() {
clearInterval(this._timer);
}
}
const slider = new Slider('slider');
slider.start();
基本方法
- 结构设计
- 展示效果
- 行为设计 -API Event
重构:插件化
解耦
- 将控制元素抽取成插件
- 插件与组件之间通过依赖注入方式建立联系
二、个人总结
此次课程,我明白了结构、表现、行为的分离是我们练习的时候需要注意的,如果将三者混在一起使用,会影响其他合作者来阅读,各司其职可以让代码更清晰,更专业。轮播图中有动态的行为,有状态绑定的过程,一般使用控制流来实现。三者也可以写在同一个文件里,最后生成的时候是各司其事、单独表现的。