资讯专栏INFORMATION COLUMN

从零开始写一个轮播

olle / 1447人阅读

摘要:什么是轮播轮播,英文,也就是幻灯片的意思,我们可以手动或者自动切换一张张的照片达到显示的目的。怎么实现一个轮播一般,我们可以两种方法来实现轮播,例如,核心思路使用透明度来切换照片,使用距离来平移照片。

什么是轮播

轮播,英文slider,也就是幻灯片的意思,我们可以手动或者自动切换一张张的照片达到显示的目的。各大电商网站都会使用轮播来展示商品,可以在相对较小的空间里,实现多种展示。

怎么实现一个轮播

一般,我们可以两种方法来实现轮播,例如,核心思路使用透明度来切换照片,使用距离来平移照片。在这里我们使用平移的方式来实现轮播,并通过几组核心数据来实现slide的切换,此外,一般还具有多种方法可以实现无缝切换。

需求分解

我们实现的轮播,所需要具有的功能可以分为以下几部分:

点击左右箭头,前后切换slide

无缝切换轮播

点击轮播中的导航按钮,切换不同的slide

初始状态会每隔3s自动切换slide

鼠标悬浮在slide上时,自动轮播停止,移出后会恢复自动轮播状态

考虑复用性,抽象为一个组件,其他如点击切换等功能考虑为插件注入

1. 向前和向后切换和无缝切换 1. 结构和样式

我们设置两个容器,通过在父容器使用transform进行左右平移,translateX()是相对于自身的宽度,而在子容器里通过绝对定位来进行平移,其中left属性相对的是父容器的宽度,这样父容器平移100%,子容器距离左边-100%,就可以相互抵消。

HTML结构如下

CSS如下,略有删减,可以参考源码

#m-slider {
  position: relative;
  width: 100%;
  height: 100%;
  transform: translateX(-100%);
}
.slide {
  position: absolute;
}
 .slide:nth-child(1) {
  left: 0%;
}
.slide:nth-child(2) {
  left: 100%;
}
.slide:nth-child(3) {
  left: 200%;
} 

此时我们知道可以显示第二张图片。

2. 前后逻辑控制

数据模型:

slideIndex为slide的索引,取值为0,1,2,表示始终只有三张图片在HTML结构当中。

offset表示当前距离最左边切换图片的数量,每次向后切换时,都会加1,取值范围为1~图片的总数量

相关说明:

normalIdx()方法是一个将数字转换为len范围的方法,接收索引和长度,返回一个在len之内的数值,这里的len固定为3

go()方法,接收1或者-1,分别表示向前和向后移动,以向前移动为例,此时做了两件事,相关所以会更新,改变容器的偏移,主要是offsetslideIndex会发生变化,都需要调用规范化方法,使其数值始终处于3之内。

calcDistance()方法为计算移动距离的方法,主要有父容器和slide的距离计算。

var slider = document.getElementById("m-slider")
var slides = document.querySelectorAll(".slide")
var prev = document.getElementById("prev");
var next = document.getElementById("next");
var slideIndex = 1; // one of 0,1,2
var offset = 1; // 显示的slide距容器最左边的偏移量

prev.onclick = function() {
    go(-1);
}
next.onclick = function() {
    go(1);
}
function normalIdx(index,len) {
  return (index + len) % len;
}
function go(foreward) {
  
  offset += foreward; // 向右移动了一个,所有偏移量也需要加一
  slideIndex += foreward; // 向右移动了一个,所以加一,需要归三化
  slideIndex = normalIdx(slideIndex,3);
  var prevIndex =  normalIdx(slideIndex - 1,3);
  var nextIndex =  normalIdx(slideIndex + 1,3);
  calcDistance(prevIndex,slideIndex,nextIndex,offset);
}
function calcDistance(prevIndex,slideIndex,nextIndex,offset) {
  slider.style.transform = `translateX(${-100*offset}%)`
  //console.log(slider.style.transform)
  console.log(offset)
  // slide offseet
  slides[prevIndex].style.left = `${100*(offset-1)}%`;
  slides[slideIndex].style.left = `${100*offset}%`;
  slides[nextIndex].style.left = `${100*(offset+1)}%`;
}
2. 无缝轮播

每次切换时,slideleft属性都会改变,父容器的transform也发生改变,相互抵消,轻松实现无缝切换,注意: 我们这里只设置了三张照片,刚好与要求一致,并没有对相关数据进行计算处理。

/** 不管轮播的照片有多少,只有三栏是常驻的
 *      -------------------
 *      |     |     |     |  
 * -------------------------------
 * |    |     |     |     |      |
 * |    |     |     |     |      |
 * |    |  1  |  2  |  3  |      |
 * |    |     |     |     |      |
 * |    |     |     |     |      |
 * -------------------------------
 *      |     |     |     |
 *      -------------------
 */
3. 面向对象化

我们将前面写的业务代码,用面向对象的思想来重构一下。

HTML发生一些改变,我们将Img通过JS动态注入

JS部分,这里`pageNum表示图片的总数量,可以为任意数字,renderImg()为渲染图片的方法,主要在切换的时候改变图片的url,第一次需要进行初始化。

// Component
class Slider {
    constructor(el) {
      // omit some code
      this.offset = 1;// 偏移量,即个数
      this.slideIndex = 1;// slide index one of 0, 1, 2
      this.pageIndex = 1;// page index of total pictures
      this.pageNum = 6;// total pictures
  }
  // 标准化index,使index始终为0,1,2中的一个
  normalIdx(index,len) {
    return (index + len) % len;
  }
  
  // slide move according to the flag
  go(flag) {
    // 1. offset and slideIndex change
    this.offset += flag;
    this.pageIndex += flag;
    const slideIndex = this.slideIndex = this.normalIdx( this.slideIndex += flag,3);
     
     // 计算移动距离
     this.calcDistance();
  }
  
  // style change
  calcDistance() {
      const offset = this.offset;
    const slideIndex = this.slideIndex;
    // index
    const prevIndex = this.normalIdx( slideIndex - 1, 3)
    const nextIndex = this.normalIdx( slideIndex + 1, 3)
    this.pageIndex = this.normalIdx(this.pageIndex,this.pageNum) 

    // 2. container and slide move
    this.container.style.transform = `translateX(${-100 * (offset)}%) `;
    this.slides[prevIndex].style.left = `${100 * (offset - 1)}%`;
    this.slides[slideIndex].style.left = `${100 * offset}%`;
    this.slides[nextIndex].style.left = `${100 * (offset + 1)}%`;
    //console.log(this.pageIndex,this.slideIndex)
    this.renderImg(this.pageIndex,this.slideIndex);
  }
  renderImg(pageIndex,slideIndex) {
      for(let i = -1; i <= 1; i++) {
      const index = (slideIndex+i+3) % 3; // 决定图片的url和left漂移
      let img = this.slides[index].querySelector("img");
      let picId = this.normalIdx( pageIndex + i, this.pageNum) + 1;
      
      // 页面初始化使用,运行一次
      if(!img) {
        img = document.createElement("img");
        this.slides[index].appendChild(img);
      }
      img.src = "http://placehold.it/300x200&text=" + picId + "-Mint";
    }
  }
  start() {
      this.bindEvents()
    this.renderImg(1,1);
  }
}

const mySlider = new Slider("m-slider");
mySlider.start()
4. 完整版

Source

添加了nav功能,点击对应的小按钮,即可跳转到指定的slide上

5. 后记

后期将考虑将轮播进行组件化,封装成独立的组件,添加更多可定制的功能。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/113430.html

相关文章

  • 从零开始一个轮播

    摘要:什么是轮播轮播,英文,也就是幻灯片的意思,我们可以手动或者自动切换一张张的照片达到显示的目的。怎么实现一个轮播一般,我们可以两种方法来实现轮播,例如,核心思路使用透明度来切换照片,使用距离来平移照片。 什么是轮播 轮播,英文slider,也就是幻灯片的意思,我们可以手动或者自动切换一张张的照片达到显示的目的。各大电商网站都会使用轮播来展示商品,可以在相对较小的空间里,实现多种展示。 怎...

    Prasanta 评论0 收藏0
  • 从零开始一个轮播

    摘要:什么是轮播轮播,英文,也就是幻灯片的意思,我们可以手动或者自动切换一张张的照片达到显示的目的。怎么实现一个轮播一般,我们可以两种方法来实现轮播,例如,核心思路使用透明度来切换照片,使用距离来平移照片。 什么是轮播 轮播,英文slider,也就是幻灯片的意思,我们可以手动或者自动切换一张张的照片达到显示的目的。各大电商网站都会使用轮播来展示商品,可以在相对较小的空间里,实现多种展示。 怎...

    hss01248 评论0 收藏0
  • 第八集: 从零开始实现一套pc端vue的ui组件库(input, textarea组件)

    摘要:第八集从零开始实现输入框组件本集定位组件是交互的一大利器他与用户的交流最为密切所以奠定了他在组件界的重要地位也算是一种如果可以的话本集也会一起说完毕竟是一个类型的一起学完收获会很大古人云组件不封输入框,一到面试就发慌一简介大家如果对这个 第八集: 从零开始实现(输入框input,textarea组件) 本集定位: input组件是交互的一大利器, 他与用户的交流最为密切, 所以奠...

    binaryTree 评论0 收藏0
  • 第八集: 从零开始实现一套pc端vue的ui组件库(input, textarea组件)

    摘要:第八集从零开始实现输入框组件本集定位组件是交互的一大利器他与用户的交流最为密切所以奠定了他在组件界的重要地位也算是一种如果可以的话本集也会一起说完毕竟是一个类型的一起学完收获会很大古人云组件不封输入框,一到面试就发慌一简介大家如果对这个 第八集: 从零开始实现(输入框input,textarea组件) 本集定位: input组件是交互的一大利器, 他与用户的交流最为密切, 所以奠...

    chanthuang 评论0 收藏0

发表评论

0条评论

olle

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<