如何封装一个组件 | 小册免费学

前言

组件封装是一个前端工程师的必经之路,一个好的组件不仅能够让你在日常开发中得到事半功倍的效果,还能提高代码的可读性。组件封装是指Web页面上抽出来一个个包含模版(HTML)、功能(Javascript)和样式(CSS)的单元。

我们以一个轮播图的功能实现为例子,最终实现的效果如下:

轮播图HTML结构

<div id="slider" class="slider-list">
  <ul>
    <li class="slider-list__item--selected">
      <img src="https://img20.360buyimg.com/pop/s1180x940_jfs/t1/165023/22/8217/33231/6039b8a5E48c6cf5f/d38e6c49e2ef0166.jpg.webp" alt="">
    </li>
    <li class="slider-list__item">
      <img src="https://img14.360buyimg.com/pop/s1180x940_jfs/t1/130459/11/12406/94820/5f86fe20E8af0be5d/e94d257788f2dca6.jpg.webp" alt="">
    </li>
    <li class="slider-list__item">
      <img src="https://img30.360buyimg.com/pop/s1180x940_jfs/t1/163816/27/10942/98525/6045e37aE6295855c/af35f9d4f5e53809.jpg.webp" alt="">
    </li>
    <li class="slider-list__item">
      <img src="https://img20.360buyimg.com/pop/s1180x940_jfs/t1/165023/22/8217/33231/6039b8a5E48c6cf5f/d38e6c49e2ef0166.jpg.webp" alt="">
    </li>
  </ul>
  <a class="slide-list_next">&gt;</a>
  <a class="slide-list_previous">&lt;</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>
</div>
复制代码

CSS样式

首先,我们给class=slider的div元素设置了宽度和高度,以及取消ul元素默认的列表样式:

.slider {
  position: relative;
  width: 790px;
  height: 340px;
}

.slider ul {
  list-style-type:none;
  position: relative;
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}
复制代码

然后,将class=slider__item和class=slider__item–selected的li元素的position属性设置为绝对定位(absolute),这样就能够将这4张图片重叠显示在同一个位置。如下代码所示:

.slider__item,
.slider__item--selected {
  position: absolute;
  transition: opacity 1s;
  opacity: 0;
  text-align: center;
}

.slider__item--selected {
  transition: opacity 1s;
  opacity: 1;
}
复制代码

接着是控制元素的样式:

.slider__next,
.slider__previous{
  display: inline-block;
  position: absolute;
  top: 50%; /*定位在录播图组件的纵向中间的位置*/
  margin-top: -25px;
  width: 30px;
  height:50px;
  text-align: center;
  font-size: 24px;
  line-height: 50px;
  overflow: hidden;
  border: none;
  color: white;
  background: rgba(0,0,0,0.2); /*设置为半透明*/
  cursor: pointer; /*设置鼠标移动到这个元素时显示为手指状*/
  opacity: 0; /*初始状态为透明*/
  transition: opacity .5s; /*设置透明度变化的动画,时间为.5秒*/
}

.slider__previous {
  left: 0; /*定位在slider元素的最左边*/
}

.slider__next {
  right: 0; /*定位在slider元素的最右边*/
}

.slider:hover .slider__previous {
  opacity: 1;
}

.slider:hover .slider__next {
  opacity: 1;
}

.slider__previous:after {
  content: '<';
}

.slider__next:after {
  content: '>';
}
复制代码

最后,定义底部四个小点的样式:

.slider__control{
  position: relative;
  display: table; /* table 布局*/
  background-color: rgba(255, 255, 255, 0.5);
  padding: 5px;
  border-radius: 12px;
  bottom: 30px;
  margin: auto;
}

.slider__control-buttons,
.slider__control-buttons--selected{
  display: inline-block;
  width: 15px;
  height: 15px;
  border-radius: 50%;/*设置为圆形*/
  margin: 0 5px;
  background-color: white;
  cursor: pointer;
}

.slider__control-buttons--selected {
  background-color: red;
}
复制代码

组件API设计

将这个组件封装为一个类——slider:

class Slider {
  constructor({container}) {
    this.container = container;
    this.items = Array.from(container.querySelectorAll('.slider__item, .slider__item--selected'));
  }

  /*
    通过选择器`.slider__item--selected`获得被选中的元素
  */
  getSelectedItem() {
    const selected = this.container.querySelector('.slider__item--selected');
    return selected;
  }

  /*
    返回选中的元素在items数组中的位置。
  */
  getSelectedItemIndex() {
    return this.items.indexOf(this.getSelectedItem());
  }

  slideTo(idx) {
    const selected = this.getSelectedItem();
    if(selected) { // 将之前选择的图片标记为普通状态
      selected.className = 'slider__item';
    }
    const item = this.items[idx];
    if(item) { // 将当前选中的图片标记为选中状态
      item.className = 'slider__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);
  }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享