使用原生js以两种方式制作一个精美的轮播图(上)

1,056 阅读7分钟

展示界面 & github源码

(这里可以实现PC端模拟移动端左右滑动图片切换的效果)

  • github源码(包含两种方式实现轮播图的源码)

前言

  • 这段时间在学习切页面的时候,发现页面上的轮播图部分让我很感兴趣,因为是刚开始学习javascript,所以想要自己手写一个轮播图,于是查阅了好多资料,发现写轮播图的方法很多很杂,虽然最终学会了如何使用js写轮播图,但是花了我好长时间。
  • 现在我想把自己总结的方法分享出来,其中第二种方法我个人觉得还是比较有价值的,在网上没有搜到类似的文章,希望给以后想写轮播图的小伙伴一点思路。

需求分析

  • 循环无缝自动轮播四张图。
  • 可以手动左右切换图片(后面我会有两种手动切换图片的方式来切换图片)。
  • 鼠标点击(触及)轮播图下面的小点可以跳转到对应的图片。
看看第一种方法写的轮播图的效果:

(这种方法移动到图片上会停止滚动,显示按钮,离开又开始滚动,隐藏按钮。)

实现原理

  • 首先理解该轮播图如何滚动,通过控制包含所有图片的父容器的left值来显示图片,在这个容器中只有和视图容器重叠的部分会显示出来,其他的都被隐藏了。
  • 为了实现“滚动”的效果,我们需要逐渐改变包含所有图片的父容器的left值,而不能直接使该值变化图片宽度的倍数。下面我们会定义一个动画效果函数Roll(),这里可以先不用管。

实现过程 & 思路

第一种轮播方式比较常见,这里我就拎重点讲,再详细讲一下js部分.CSS和HTML代码请到github源码中查看.

HTML部分

  • 这里用了三个盒子,最外层id为parent的大盒子内包含了uls和buttons两个盒子,盒子uls中包含了两个列表img_ul(图片列表)和litCir_ul(小圆点列表),盒子buttons里则包含了“左”,“右”两个按钮。

CSS部分

  • 这里css需要注意的是uls设置了overflow: hidden;所以它的子容器img_ul只会显示和uls盒子重叠的部分,其他部分隐藏;
  • 给img_ul设置宽度要长多出一张图片的宽度,用以放后面克隆的图片(js部分会详细讲);

JS部分

// 这里我们先添加小圆点,让页面显示完整,之所用js添加小圆点,
是因为小圆点的数量应该由图片张数决定的。
for(let i = 0; i < len;i++){
var a_li = document.createElement('li');//创建li元素节点
a_li.className = 'quiet';//给li添加类名quiet
litCir_ul.appendChild(a_li);
}
  • 将会在下面用到的Html中的对象和一些变量
/*获取HTML中的对象*/
var parent = document.getElementById("parent");
var img_ul = document.getElementById("img_ul");
var litCir_ul = document.getElementById("litCir_ul");
var buttons = document.getElementById("buttons");
var cLis =litCir_ul.children;         //children 属性返回元素的子元素的集合
//定义一些变量
var len = img_ul.children.length;     //图片张数
var width = parent.offsetWidth;       //每张图片的宽度
var rate = 15;                        //一张图片的切换速度, 单位为px
var times = 1;                        //切换速度的倍率
var gap = 2000;                       //自动切换间隙, 单位为毫秒
var timer = null;                     //初始化一个定时器
var picN = 0;                         //当前显示的图片下标
var cirN = 0;                         //当前显示图片的小圆点下标
var temp;
  • 首先理解无缝滚动是怎么做到的,这里定义一个动画效果函数Roll();通过传进来的distance来控制img_ul的位置来显示,设置img_ul的left值,以达到图片滚动的.
function Roll(distance){                                         //参数distance:滚动的目标点(必为图片宽度的倍数)
    clearInterval(img_ul.timer);                                     //每次运行该函数必须清除之前的定时器!
    var speed = img_ul.offsetLeft < distance ?  rate : (0-rate);     //判断图片移动的方向  此处用了三元运算符  ? 前面的不等式成立时为rate,不成立时为0-rete
        // console.log(speed)
    img_ul.timer = setInterval(function(){                           //设置定时器,每隔10毫秒,调用一次该匿名函数
        img_ul.style.left = img_ul.offsetLeft + speed + "px";        //每一次调用滚动到的地方 (速度为 speed px/10 ms)       offsetLeft为元素边框外侧到父元素边框内侧的距离    
        var leave = distance - img_ul.offsetLeft;                    //距目标点剩余的px值      
        /*接近目标点时的处理,滚动接近目标时直接到达, 避免rate值设置不当时不能完整显示图片*/
        if (Math.abs(leave) <= Math.abs(speed)) {                    
            clearInterval(img_ul.timer);
            img_ul.style.left = distance + "px";
        }
    },10);
    }
  • 当图片从最后一张切换到第一张时,这时就不能通过逐渐改变img_ul的left值来实现滚动的效果,于是克隆第一张图片至列表尾部,当滚动完最后一张图片时,继续滚动到克隆的第一张,然后将img_ul的left值重置为0。
img_ul.appendChild(img_ul.children[0].cloneNode(true));//克隆第一张图片至列表尾部
  • 定义自动滚动函数autoRun()
function autoRun(){
        picN++
        cirN++
        //如果轮播完克隆项应该轮播回第二张照片上,因为克隆项和第一张图片一样
        if(picN > len) {
            img_ul.style.left = 0;//改变left至真正的第一项处,这个过程是时间太快太短所以可以忽略不计然后立刻
            picN = 1;   //从第二张开始显示
        }
        // 自动轮播,当图片为第一张时应该自动到第二张上去,所以要传入第二张的picN值,依次类推
        Roll(-picN*width)
        //判断是否到了最后一个圆点,当圆点到了最后一个时,应该变回第一个点进行轮播
        if (cirN > len - 1) {
            cirN = 0;
        }
        for(var i = 0; i < len;i++) {
            cLis[i].className = 'quiet';//让所有圆点背景色变为默认色
        }
        cLis[cirN].className = 'active';
    }
  • 注意:以上轮播图片时是当图片索引值picN已经有了,要+1,等待一定时间执行移动到下一张图片的事件
    开始自动滚动:
    timer = setInterval(autoRun, gap); //定时器
    
  • 给小圆点设置触及事件
    for(let j = 0;j < len ;j++){
        cLis[j].index = j;//给每个圆点一个索引值
        cLis[j].onmouseover = function() {
            for(var k = 0; k < len;k++) {
                cLis[k].className = 'quiet';//让所有圆点背景色变为默认色
            }
            this.className = 'active';
            temp = cirN;
            picN = cirN = this.index;
            times = Math.abs(this.index - temp);//距离上个小圆点的距离
            rate = rate*times;//根据距离改变切换速率
            Roll(-this.index * width);
            rate = 15;
        }
    }
    
  • 接下来是触及轮播图区域,图片停止轮播,显示左右按钮,离开该区域时,又重新开始定时器的自动轮播,左右按钮隐藏.
    //触及轮播图区域,清除定时器
    parent.onmouseover = function(){
        clearInterval(timer);
        buttons.style.display = 'block';
    }//离开该区域时,重新开始定时器的自动轮播
    parent.onmouseout = function(){
        buttons.style.display = 'none';
        timer = setInterval(autoRun, gap);
    }
    
  • 下面是设置左右按钮点击切换图片的事件.
    //给左边按钮添加点击事件
    buttons.children[0].onclick = function() {
        picN--;
        cirN--;
        if(picN < 0){
            img_ul.style.left = -len*width + 'px';
            picN = len - 1;
        }
        Roll(-picN*width);
        if(cirN < 0){
            cirN = len - 1;
        }
        for(var i = 0; i < len; i++) {
            cLis[i].className = 'quiet';
        }
        cLis[cirN].className = 'active';
    }
    //给右边按钮添加点击事件
    buttons.children[1].onclick = autoRun;
    //自动播放就是间隔一定时间不断调用函数“下一张”的过程,所以这里的
    按钮right下一张的实现就是上面的autoRun函数。
    

总结

本来想写两种方式实现轮播图的,由于第一次在掘金社区里写文章,没有控制好字数,感觉写的太长太多了,所以这里先写第一种原生js方式的实现轮播图。如果想了解第二种原生js是如何实现轮播图的话,我会继续更新的哦!请持续关注,这也是笔者的第一篇文章,如果各位看官喜欢请点赞收藏,这对笔者是莫大的鼓励😊。