这是我参与「第五届青训营 」笔记创作活动的第4天
课程重点
- JavaScript 好代码的标准
- HTML/CSS/JS 各司其责
- 组件的定义解析及特征
- 组件封装基本方法
- 利用原生 JS 实现电商网站轮播图
- 过程抽象概念
- 高阶函数使用模式
- JavaScript 编程范式
写好JS的一些原则
- 各司其职----让HTML、CSS和JavaScript职能分离
- 组件封装----好的UI组件具备正确性、扩散性、复用性
- 过程抽象----应用函数式编程思想
各司其责
各司其责-例子
写一段JS,控制一个网页,让它支持浅色和深色两种浏览模式。 如果是你来实现,你会怎么做?
深夜食堂:版本一
深夜食堂:版本二
深夜食堂:版本三
深夜食堂:结论
- HTML/CSS/JS各司其职
- 应该避免不必要的由JS直接操作样式
- 可以用class来表示状态
- 纯展示类交互寻求零JS方案
组件封装-例子
用原生JS写一个电商网站的轮播图,应该怎么实现?
组件是指Web页面上抽出来一个个包含模版(HTML)、功能(JS) 和样式(CsS) 的单元。 好的组件具备封装性、正确性、扩展性、复用性。
结构设计:HTML
轮播图是一个典型的列表结构,我们可以使用无序列表
- 元素来实现。
<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绝对定位讲图片重叠在同一个位置
- 轮播图切换的状态使用修饰符(modifier)
- 轮播图的切换动画使用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;
}
行为设计:API
-
API设计应保证原子操作,职责单一,满足灵活性。
-
Slider
- +getSelectedItem()
- +getSelectedItemIndex()
- +slideTo()
- +slideNext()
- +slidePrevious()
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);
}
}
行为设计:控制流
- 使用自定义事件来解耦
<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 CusstommEvent('slide',{bubbles:true,detail})
this.container.dispatchEvent(event)
组件封装
总结:基本方法
- 结构设计
- 展现效果
- 行为设计
- API(功能)
- Event(控制流)
重构:插件化
解耦
- 讲控制元素抽取成插件
- 插件与组件之间通过依赖注入方式建立联系
重构:模板化
解耦
- 将HTML模板化,更易于扩展
重构:组件框架
抽象
- 将通用的组件模型抽象出来
总结
- 组件设计的原则:封装性、正确性、扩散性、复用性
- 实现组件的步骤:结构设计、展现效果、行为设计
- 三次重构
- 插件化
- 模板化
- 抽象化(组件框架)
过程抽象
- 用来处理局部细节控制的一些方法
- 函数式编程思想的基础应用
过程抽象-例子
操作次数限制
- 一些一步交互
- 一次性的HTTP请求
Once
- 为了能够让“只执行一次”的需求覆盖不同的事件处理,我们可以将这个需求剥离出来,这个过程我们称为过程抽象
高阶函数
- 以函数作为参数
- 以函数作为返回值
- 常用于作为函数装饰器
常用高阶函数
命令式与声明式
例子
总结
- 过程抽象/HOF/装饰器
- 命令式/声明式