JS组件封装

123 阅读2分钟

这是我参与「第五届青训营 」笔记创作活动的第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 编码原则之组件封装