发布于 

组件化封装

JS组件封装

基本方法(以轮播图组件为例)

  • 结构设计
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <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>
  • 展现效果
  • 行为设计
    • API(功能)
    • Event(控制流)
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      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
  • 可复用性差,多次使用该组件需要多次复制相同的代码

如何改进?

重构

插件化

解耦

  • 将控制元素抽取成插件
    1
    2
    3
    registerPlugins(...plugins){
    //abstract
    };
  • 插件与组件通过依赖注入方式建立联系
    1
    2
    3
    4
    5
    6
    7
    8
    9
    const pluginController = {
    //abstract
    action(slider){
    //abstraction
    }
    }
    const pluginPrevious = {
    //abstract
    }
    通过把组件的组成部分抽象成插件,我们只要在使用该组件时传入要注册的插件,就可以方便的实现组件的增删,并且后来如果还要编写新的插件也可以按原逻辑在原有js上增加。

    模板化

  • 将HTML模板化。更易于扩展
    在插件的render方法中把组件的html模板化,
    1
    2
    3
    render(){
    return `<a class="slide-list__previous"></a>`;
    },
    此时,组件的html代码只有短短一行
    1
    <div id="my-slider" class="slider-list"></div>

    抽象化(组件框架)

  • 将组件通用模型抽象出来
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    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。

总结

  • 组件设计的原则:封装性、正确性、复用性、扩展性
  • 实现组件的步骤:结构设计、展现效果、行为设计
  • 三次重构
    • 插件化
    • 模板化
    • 抽象化

本站由 @Eureka 使用 Stellar 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。