【青训营】- 代码分析 分析一个 Slider 代码

521 阅读2分钟

分析一个轮播图实例

HTML 分析

<div id="my-slider" class="slider-list">
    <ul>
        <li class="slider-list__item--selected">
            <img src="https://p5.ssl.qhimg.com/t0119c74624763dd070.png"/>
        </li>
        <li class="slider-list__item">
            <img src="https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg"/>
        </li>
        <li class="slider-list__item">
            <img src="https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg"/>
        </li>
        <li class="slider-list__item">
            <img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg"/>
        </li>
    </ul>
    <a class="slide-list__next"></a>
    <a class="slide-list__previous"></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>

div#my-slider 作为轮播图容器,包括了一个轮播图 ul 和控制流( a.slide-list__next, a.slide-list__previous, div.slide-list__control )。

内容是静态的所以说我们增删都需要直接修改 HTML 文件结构,修改组件也是需要直接修改 HTML ,这样会导致维护起来比较困难。

CSS 分析

这里有一个有意思的地方

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

这里边的 bottom 是相对上一个元素 ul 定位的,如果改成 top 的话,就会相对下一个元素定位(这里没有所以会沉下去)。

在处理前后翻页的时候,没有在 a 标签内直接写&lt;&gt;,而是在后边加了一个伪元素:after,可能是因为不能选中的关系,不过也是挺巧妙的,第一次遇到。

.slide-list__previous:after {
    content: '<';
}

.slide-list__next:after {
    content: '>';
}

JS 分析

JS这部分分析比较头疼,第一次遇到,不过大受震惊。

分析 Slider

class Slider{
    ...
    registerPlugins(...plugins){
      plugins.forEach(plugin => plugin(this));
    }
    ...
}

注册插件这里看了半天,遍历 plugins ,对于每个子项 plugin ,把它当做方法并调用,参数 this 指的是 Slider 本身。

举例子:

slider.registerPlugins(pluginController, pluginPrevious, pluginNext);

等价于

pluginController(slider);
pluginPrevious(slider);
pluginNext(slider);

下一部分 slideTo 函数

class Slider{
    ...
    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';
      }

      const detail = {index: idx}
      const event = new CustomEvent('slide', {bubbles:true, detail})
      this.container.dispatchEvent(event);
      ...
}
}

上方很好理解,获取已选中的 item 取消样式,获取将要选中的 item 设置样式,下边 new 了一个自定义事件:事件名叫做 slide ,冒泡,有一个参数 index;然后派发给 slider 容器。

分析 Controller

开头很容易理解(代码已省略),鼠标经过跳转,停止 cycle,离开继续 cycle

重点看一下 slide 的事件监听

function pluginController(slider){
    ...
    slider.addEventListener('slide', evt => {
      const idx = evt.detail.index
      const selected = controller.querySelector('.slide-list__control-buttons--selected');
      if(selected) selected.className = 'slide-list__control-buttons';
      buttons[idx].className = 'slide-list__control-buttons--selected';
    });
    ...
}

流程大概这样的:

  1. 获取事件参数——新的index
  2. 获取已经选到的小圆点
  3. 将其样式复原
  4. 将新的index设置样式

整体流程是这样的:

  1. 鼠标悬浮到小圆点上(mouseover监听)
  2. 跳转到指定 itemslider.slideTo(idx)
  3. 触发 slide 事件 (dispatchEvent(event)
  4. 捕获 slide 事件 (slide监听)
  5. 改变小圆点样式

NextPrevious的流程跟上方分析基本一样,不过是将 mouseover 监听替换了 click 监听。

个人总结

我之前也写过一些简单的静态网页,但是很一次性,基本不具备复用性,第一次看见这么厉害的代码还是比较激动的,分析了挺长时间。

同时,如果有误请指正。

参考

  1. CustomEvent - Web API 接口参考 | MDN (mozilla.org)
  2. EventTarget.dispatchEvent - Web API 接口参考 | MDN (mozilla.org)
  3. event.preventDefault - Web API 接口参考 | MDN (mozilla.org)