这是我参与「第五届青训营 」笔记创作活动的第1天
JS组件封装
前言:在前端开发中我们用到组件的场景很多,前端也有很多组件库,例如:vant,element-ui等等,但在实际开发中,组件库的组件不一定能满足我们的要求,那么我们就要封装自己的组件了。 今天月影老师就带我们封装一个轮播图组件。
基本方法(以轮播图组件为例)
- 结构设计
<div id="my-slider" class="slider-list">
<ul>
<li class="slider-list__item--selected">
<img src="xx.png"/>
</li>
<li class="slider-list__item">
<img src=""/>
</li>
<li class="slider-list__item">
<img src=" "/>
</li>
<li class="slider-list__item">
<img src=""/>
</li>
</ul>
</div>
- 展现效果 效果由css实现,再通过js控制类名
- 行为设计
- API(功能)
- Event(控制流)
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);
}
}
但是这样功能虽然实现,但是
- 可扩展性差,例如假如要加导航栏,既要改js,还要对应加上html和css
- 可复用性差,多次使用该组件需要多次复制相同的代码 如何改进?
重构
插件化
解耦
- 将控制元素抽取成插件
registerPlugins(...plugins){
//abstract
});
}
- 插件与组件通过依赖注入方式建立联系
const pluginController = {
//abstract
},
action(slider){
//abstraction
}
};
const pluginPrevious = {
//abstract
}
通过把组件的组成部分抽象成插件,我们只要在使用该组件时传入要注册的插件,就可以方便的实现组件的增删,并且后来如果还要编写新的插件也可以按原逻辑在原有js上增加。
模板化
- 将HTML模板化。更易于扩展 在插件的render方法中把组件的html模板化,
render(){
return `<a class="slide-list__previous"></a>`;
},
此时,组件的html代码只有短短一行
<div id="my-slider" class="slider-list"></div>
抽象化(组件框架)
- 将组件通用模型抽象出来
class Component {
constructor(id, opts = { name, data: [] }) {
this.container = document.getElementById(id);
this.options = opts;
this.container.innerHTML = this.render(opts.data);
}
registerPlugins(...plugins) {
//abstract
}
render(data) {
//abstract
return "";
}
}
这里把通用的组件模型抽象为一个Component类,后来增添新组件可通过extend关键字来继承这个component。
总结
- 组件设计的原则:封装性、正确性、复用性、扩展性
- 实现组件的步骤:结构设计、展现效果、行为设计
- 三次重构
- 插件化
- 模板化
- 抽象化 不得不感慨高级工程师写出的代码确如诗般美丽。
文中代码引用自JavaScript 编码原则之组件封装