组件是指Web页面上抽出来一个个包含模版(HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。
例子:轮播图
如果要你用原生JS写一个电商或视频网站上常见的轮播图,应该怎么实现?怎么封装成组件?怎么让它的扩展性和复用性更高?
1. 结构设计
轮播图是一个典型的列表结构,我们可以用无序列表ul>li*4
来实现,然后根据效果图插入4张图片即可:
这里我们使用的命名是一种CSS的书写规范,叫做BEM
,是英文Block-Element-Modifier
的简写,这一规范采用三个部分来描述规则,其中:
__
:双下划线用来连接块和块的子元素-
:单中划线仅作为连字符使用,连接块或元素或修饰符的多个单词--
:双中划线用来连接块或元素的状态这样命名可以将用户界面分隔为独立的块,从而使开发复杂的UI界面变得更简单,代码可读性也更强。
上面的HTML结构中,我们使用a
元素分别表示上一张和下一张:
<a class="slider__previous"></a> <a class="slider__next"></a> 复制代码
用span*4
表示底部的四个小圆点:
<div class="slider__control"> <span class="slider__control-buttons--selected"></span> <span class="slider__control-buttons"></span> <span class="slider__control-buttons"></span> <span class="slider__control-buttons"></span> </div> 复制代码
2. 展现效果
根据效果图我们继续添加CSS样式,首先设置宽高,隐藏列表样式:
.slider { position: relative; width: 790px; height: 340px; } .slider ul { list-style-type:none; position: relative; width: 100%; height: 100%; padding: 0; margin: 0; } 复制代码
将图片重叠,只显示.slider__item--selected
:
.slider__item, .slider__item--selected { position: absolute; transition: opacity 1s; opacity: 0; /* 完全透明 */ text-align: center; } .slider__item--selected { transition: opacity 1s; opacity: 1; } 复制代码
能够上下切换的左右箭头:
最后定义底部的4个小圆点:
3. API设计
API的设计应保证原子操作,职能单一,满足灵活性。
我们先简单分析一下需求:
- 图片循环播放,每张停留若干时间
- 点击左右箭头可以上下切换
- 鼠标悬浮在底部小圆点上时会跳到对应图片
- 小圆点也会随着图片滚动
根据需求和月影大大的设计要求,我们设计了几个组件API:
将其封装成一个类:
然后通过setInterval()
实现循环播放,间隔为3秒:
const container = document.querySelector('.slider'); const slider = new Slider(container); setInterval(() => { slider.slideNext(); }, 3000); 复制代码
4. 用户控制
在JS代码中,一个方法一般来说最多只能有15行代码,超过了就需要重构。
实现了API后,我们需要实现用户控制,根据需求修改构造器:
用定时器来实现stop()
和start()
,当鼠标移动到小圆点上(mouseover),判断是第几个小圆点,停止循环播放,切换到对应图片,当鼠标移出后(mouseout)再开始循环。
start() { this.stop(); this._timer = setInterval(() => this.slideNext(), this.cycle); } stop() { clearInterval(this._timer); } 复制代码
然后我们处理自定义的slide事件,修改slideTo()
:
slideTo(idx) { ... // 触发自定义事件slide const detail = {index: idx}; const event = new CustomEvent('slide', {bubbles: true, detail}); this.container.dispatchEvent(event); } 复制代码
最后将调用过程修改一下,组件的全部功能就完成了。
const container = document.querySelector('.slider'); const slider = new Slider({container}); slider.start(); 复制代码
通过轮播图组件编写过程,我们可以总结一下组件设计的一般性步骤:
- 结构设计和展现效果(HTML&CSS)
- 设计组件API
- 设计用户控制流程
我们实现的轮播组件实现了封装性和正确性,但是缺少了可扩展性,这个组件只能满足自身的使用,很难扩展到其他的组件。而且当有功能变化时,也需要修改其自身内部的代码。
比如当产品经理希望将图片下方的小圆点去掉只保留左右箭头时,在这个版本中我们就需要注释或修改所有与小圆点相关的代码,而且当有新的用户控制需求时,我们都需要涉及核心代码的修改,所以如何避免这样的修改,让组件具备可扩展性和复用性就是我们下节要做的事情了。