【PC端网页特效】04-原生JS实现网页轮播图详解

网页轮播图

  • 网页轮播图案例
    • 结构搭建
      • 初期项目结构
      • 存在的问题并解决
      • 完整结构和项目准备
    • 需求分析
    • 功能实现
      • 1. 鼠标经过显示左右隐藏按钮
      • 2. 动态生成小圆圈
      • 3. 小圆圈排他思想
      • 4.点击小圆圈滚动图片
      • 5.按钮功能
      • 6.添加定时器并修改bug
      • 7. 添加节流阀
    • 网页轮播图JS文件

网页轮播图案例

轮播图也称为焦点图,是网页中比较常见的网页特效。

结构搭建

因为html和css阶段看的尚硅谷课程,所以采用课程中的小米商城项目,在项目搭建的过程中遇到一个经典问题

初期项目结构

最初的效果:
【PC端网页特效】04-原生JS实现网页轮播图详解_第1张图片
HTML代码:

    <div class="banner-wrap">
        <div class="banner w">
           <ul class="img-list clearfix">
           <li><a href="#"><img src="./img/banner2.png" alt="">a>li>
           <li><a href="#"><img src="./img/banner3.png" alt="">a>li> 
            <li><a href="#"><img src="./img/banner1.png" alt="">a>li>
           ul>
            
           
           <div class="pointer">
            <a class="active" href="#">a>
            <a href="#">a>
            <a href="#">a>
          div>
          
          <div class="prev-next">
            <a class="prev" href="#">a>
            <a class="next" href="#">a>
          div>
        div>
    div>

最初的css代码:

.banner{
    position: relative;
    height: 460px;
}
.banner .img-list{
    /* 因为有三张图片,所有设置吧ul宽度设置为banner的3倍 */
    width: 300%;
   
    
}
/* 让banner中的li图片横向排列 */
.banner .img-list li{
   float: left;

    
}
/* 设置轮播图 */
.banner img{
     width: 100%; 
    vertical-align: top;
}

存在的问题并解决

  • 在初期的项目中,因为没有学习JS,网页中banner的实现方法是为装有img图片的li容器设置了绝对定位,把所有的图片都覆盖住了;
  • 当按需要给li的父级(img-list)设置为400%,把li的绝对定位清除并设置为向左浮动时:网页中没有出现预期的li正常横向排列,而是出现如下图所示


【PC端网页特效】04-原生JS实现网页轮播图详解_第2张图片
问题1:img和li宽度均变为图片本身的宽度,而非最初的banner宽度
问题分析::因为img中的wdith设置为100%,宽度由banner继承而来,而当li设置向左浮动时,img无处继承,li也被img撑开,所以宽度均变为图片本身的宽度
解决方法:为img设置宽度,此处设置为1226px;

问题2:修改后li的位置仍为发生改变
问题分析:为元素开启了向左浮动且前边没有其他浮动元素,所以应该向左浮动且不会从父元素中移出;没有发生改变的原因是因为li浮动开启BFC时,父元素img-list高度塌陷而绝对定位也移出,所以位置异常
解决方法:为img-list添加clearfix
(链接高度塌陷和外边距重叠原理及解决方案)

html改动处代码:

 <ul class="img-list clearfix">
           <li><a href="#"><img src="./img/banner2.png" alt="">a>li>
           <li><a href="#"><img src="./img/banner3.png" alt="">a>li> 
            <li><a href="#"><img src="./img/banner1.png" alt="">a>li>
           ul>

css修改后代码:

.banner .img-list{ 
    width: 400%;
}
/* 让banner中的li图片横向排列 */
.banner .img-list li{
   float: left;
 }
/* 设置轮播图 */
.banner img{
    width: 1226px;
    vertical-align: top;
}

修改后达到预期效果
【PC端网页特效】04-原生JS实现网页轮播图详解_第3张图片

完整结构和项目准备

【PC端网页特效】04-原生JS实现网页轮播图详解_第4张图片

  • 在index.html中引入animate.js和index.js,因为后续index.js中会用到animate所以,animate.js要放在index.js上边引入
  • 因为js是写在外部的,所以在JS中要添加load事件,页面加载完毕再调用js
  • 动画函数js文件链接:anlimate.js

需求分析

轮播图也称为焦点图,是网页中比较常见的网页特效。

功能需求:

  1. 鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。
  2. ​点击右侧按钮一次,图片往左播放一张,以此类推,左侧按钮同理。
  3. ​ 图片播放的同时,下面小圆圈模块跟随一起变化。
  4. ​ 点击小圆圈,可以播放相应图片。
  5. 鼠标不经过轮播图,轮播图也会自动播放图片
  6. ​ 鼠标经过,轮播图模块, 自动播放停止。

功能实现

以下的所有JS代码中若有不知道的class名,可返回上方查看html结构

1. 鼠标经过显示左右隐藏按钮

  1. 在css中将左右按钮的display设置为none来隐藏按钮
  2. 让鼠标经过轮播图模块,左右按钮显示,离开隐藏左右按钮。

JS代码:

window.addEventListener('load', function(){
    // 获取元素
    var prev = document.querySelector('.prev');
    var next = document.querySelector('.next');
    var banner = document.querySelector('.banner');
    var bannerWidth = banner.offsetWidth;
    // 鼠标经过banner显示隐藏左右按钮
    banner.addEventListener('mouseenter', function(){
        prev.style.display = 'block';
        next.style.display = 'block';
    })
    banner.addEventListener('mouseleave', function(){
        prev.style.display = 'none';
        next.style.display = 'none';
 
    })

2. 动态生成小圆圈

核心思路:小圆点的个数要与banner图片张数一致:有几张图 就生成几个小圆圈

  1. 首先获取 ul中包裹图片的li数量:有多少张图,就有多少li

  2. 以li的数量循环动态创建小圆圈: createElement(‘a’)

  3. 将生成的a(小圆圈)添加到 pointer中 :pointer.appendChild(a);

  4. 为第一个小圆圈需要添加 current 类

 var ul = banner.querySelector('ul');
    var pointer = document.querySelector('.pointer');
    for(var i =0; i<ul.children.length; i++){
        pointer.appendChild(a);
     }   
  // 把pointer里面的第一个a设置类名为current
    pointer.children[0].className = 'current';

3. 小圆圈排他思想

  1. 点击当前小圆圈,就添加 current 类(current类中是选中的独特样式)
  2. 其余的小圆圈就移除这个 current 类
  3. 上方生成小圆圈的同时,就可以直接绑定这个点击事件了。
//生成每一个a小圆圈同时添加点击事件
         a.addEventListener('click', function(){
            // (排他思想使小圆圈唯一current类名)
            // 清除每一个小圆圈的current类名
            for(var i = 0; i<ul.children.length-1; i++){//此处减一的原因要深究:异步
                pointer.children[i].className = '';
            }
            // 只留下点击的小圆圈  current样式
            this.className = 'current';

4.点击小圆圈滚动图片

  1. 此时用到准备时在index.js上方引入的animate.js
  2. 使用动画函数的前提,该元素必须有定位,此处是ul(即img-list)
  3. 滚动图片的核心算法:点击某个小圆圈,就让图片滚动小圆圈的索引号乘以图片的宽度做为 ul 移动距离
  4. 此时需要知道小圆圈的索引号,我们可以在生成小圆圈的时候,给它设置一个自定义属性,点击的时候获取这个自定 义属性即可

css代码:

.banner .img-list{ 
    width: 500%;
    position: absolute;
    top: 0;
    left: 0;
}

JS代码:

 // 3.动态生成小圆圈,有几张图 就生成几个小圆圈
    var ul = banner.querySelector('ul');
    var pointer = document.querySelector('.pointer');
    for(var i =0; i<ul.children.length; i++){
        // 创建小圆圈
        var a = document.createElement('a');
        // 记录当前小圆圈的索引号 通过自定义属性来做
        a.setAttribute('index',i);
        // 添加小圆圈
        pointer.appendChild(a);
        // 
    // 4.生成每一个a小圆圈同时添加点击事件
         a.addEventListener('click', function(){
            // (排他思想使小圆圈唯一current类名)
            // 清除每一个小圆圈的current类名
            for(var i = 0; i<ul.children.length-1; i++){//此处减一的原因要深究:异步
                pointer.children[i].className = '';
            }
            // 只留下点击的小圆圈  current样式
            this.className = 'current';
    // 5.点击小圆圈,移动图片,移动的是ul(img-list)
            // ul的移动距离就是小圆圈的索引号 乘以 图片的宽度(负值)
            // 当我们点击了哪个小圆圈a,就获得它的索引号
            var index = this.getAttribute('index');
            animate(ul, - index*bannerWidth);

5.按钮功能

点击一次,滚动一张图片;点击按钮时,小圆圈也随着变化

  1. 声明一个变量 num,点击一次,自增 1,让这个变量乘以图片宽度,就是ul 的滚动距离。
  2. 克隆一张图片
  3. 声明一个circle变量控制小圆圈
  4. 图片无缝滚动原理:把 ul 第一个 li 复制一份,放到 ul 的最后面,当图片滚动到克隆的最后一张图片时,让 ul 快速的、不做动画的跳到最左侧:left 为0;同时 num 赋值为0,可以从新开始滚动图片了
  5. 左侧按钮同理,只需修改一些细节
// 6.克隆第一张图片(li)放到ul最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7.点击右侧按钮,图片滚动一张
    var num = 0;
    // circle控制小圆圈的播放
    var circle = 0;
    next.addEventListener('click', function(){

         //无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
        if(num == ul.children.length -1){
            ul.style.left = 0;
            num = 0;
        }
        num++;
        animate(ul, - num*bannerWidth)
 
    // 8.点击右侧按钮,小圆圈也跟随变化,可以在声明一个变量circle
        circle++;
        // 如果circle =3,就说明走到最后一张图片了(克隆的那张)我们就复原
         if(circle == pointer.children.length){
             circle =0;
         }
        // 调用函数
        circleChange();
        }
    })
// 9.左侧按钮设置
    prev.addEventListener('click', function(){
          //无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
          if(num == 0){
            num = ul.children.length-1;
            ul.style.left = - num*bannerWidth + 'px';
        }
        num--;
        animate(ul, - num*bannerWidth)

    // 点击左侧按钮,小圆圈也跟随变化,可以声明一个变量circle
        circle--;
        // 如果circle小于0,说明小圆圈选中状态跳到最后一张上
         if(circle < 0){
             circle =pointer.children.length-1;
         }

        circleChange();
        
      }
    })
    //将小圆圈排他封装成函数
    function circleChange(){
        // 先清除其他小圆圈的样式
        for(var i = 0; i<pointer.children.length; i++){
            pointer.children[i].className = '';
        }
        // 留下当前小圆圈的current
        pointer.children[circle].className = 'current';
    }
           

6.添加定时器并修改bug

bug:点击左右侧按钮和小圆圈均可实现对应的功能;但若先点击小圆圈(如点最后一个),再点击右侧按钮,此时会发现跳转到了第二张图片而不是第一张,这是因为按钮滚动图片时是用num值控制,而点击小圆圈为对其造成影响;同理小圆点也有异常情况

解决方法:在点击小圆圈时,把索引号赋值给num和circle

 // 5.点击小圆圈,移动图片,移动的是ul(img-list)
            // ul的移动距离就是小圆圈的索引号 乘以 图片的宽度(负值)
            // 当我们点击了哪个小圆圈a,就获得它的索引号
            var index = this.getAttribute('index');
            animate(ul, - index*bannerWidth);
            // 点击小圆圈后,把小圆圈索引号赋值给num:右侧按钮通过num控制图片移动
            num = index;//不加此代码:通过小圆点跳到最后一张图,点击右侧按钮 发现跳到第二张图,因为点击时num没发生改变,而箭头通过num控制
            // 点击小圆圈后,把小圆圈索引号赋值给circle:circle控制小圆圈的样式
            circle = index;

添加定时器

  1. 添加一个定时器
  2. 自动播放轮播图,实际就类似于点击了右侧按钮
  3. 此时我们使用手动调用右侧按钮点击事件 next.click()
  4. 鼠标经过 banner 就停止定时器
  5. 鼠标离开 banner 就开启定时器
    // 10.自动播放轮播图
    var timer = setInterval(function(){
        // 手动调用事件
        next.click();
    },3000)

7. 添加节流阀

  1. 功能:防止轮播图按钮连续点击造成播放过快。
  2. 原理:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。

思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
开始设置一个变量:var flag = true; if(flag) {flag = false; do something}:关闭水龙头
利用回调函数动画执行完毕:flag = true 打开水龙头

网页轮播图JS文件

  • 实现效果:

【PC端网页特效】04-原生JS实现网页轮播图详解_第5张图片

  • JS代码:
window.addEventListener('load', function(){
    // 1.获取元素
    var prev = document.querySelector('.prev');
    var next = document.querySelector('.next');
    var banner = document.querySelector('.banner');
    var bannerWidth = banner.offsetWidth;
    // 2.鼠标经过banner显示隐藏左右按钮
    banner.addEventListener('mouseenter', function(){
        prev.style.display = 'block';
        next.style.display = 'block';
        clearInterval(timer);
        timer = null;//清除定时器变量
    })
    banner.addEventListener('mouseleave', function(){
        prev.style.display = 'none';
        next.style.display = 'none';
        timer = setInterval(function(){
            // 手动调用事件
            next.click();
        },3000)
    })
    // 3.动态生成小圆圈,有几张图 就生成几个小圆圈
    var ul = banner.querySelector('ul');
    var pointer = document.querySelector('.pointer');
    for(var i =0; i<ul.children.length; i++){
        // 创建小圆圈
        var a = document.createElement('a');
        // 记录当前小圆圈的索引号 通过自定义属性来做
        a.setAttribute('index',i);
        // 添加小圆圈
        pointer.appendChild(a);
        // 
    // 4.生成每一个a小圆圈同时添加点击事件
         a.addEventListener('click', function(){
            // (排他思想使小圆圈唯一current类名)
            // 清除每一个小圆圈的current类名
            for(var i = 0; i<ul.children.length-1; i++){//此处减一的原因要深究:异步
                pointer.children[i].className = '';
            }
            // 只留下点击的小圆圈  current样式
            this.className = 'current';
    // 5.点击小圆圈,移动图片,移动的是ul(img-list)
            // ul的移动距离就是小圆圈的索引号 乘以 图片的宽度(负值)
            // 当我们点击了哪个小圆圈a,就获得它的索引号
            var index = this.getAttribute('index');
            animate(ul, - index*bannerWidth);
            // 点击小圆圈后,把小圆圈索引号赋值给num:右侧按钮通过num控制图片移动
            num = index;//不加此代码:通过小圆点跳到最后一张图,点击右侧按钮 发现跳到第二张图,因为点击时num没发生改变,而箭头通过num控制
            // 点击小圆圈后,把小圆圈索引号赋值给circle:circle控制小圆圈的样式
            circle = index;

            
        })
    }
    // 把pointer里面的第一个a设置类名为current
    pointer.children[0].className = 'current';

        
    // 6.克隆第一张图片(li)放到ul最后面
    var first = ul.children[0].cloneNode(true);
    ul.appendChild(first);
    // 7.点击右侧按钮,图片滚动一张
    var num = 0;
    // circle控制小圆圈的播放
    var circle = 0;
    // 节流阀
    var flag = true;
    next.addEventListener('click', function(){
        if (flag){
            flag =false;//关闭节流阀
            //无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
        if(num == ul.children.length -1){
            ul.style.left = 0;
            num = 0;
        }
        num++;
        animate(ul, - num*bannerWidth, function(){
            flag = true;//打开节流阀
        });
    // 8.点击右侧按钮,小圆圈也跟随变化,可以在声明一个变量circle
        circle++;
        // 如果circle =3,就说明走到最后一张图片了(克隆的那张)我们就复原
        // if(circle == pointer.children.length){
        //     circle =0;
        // }
        // 优化:
        circle = circle == pointer.children.length? 0 :circle;
        // 调用函数
        circleChange();
        }
    })
// 9.左侧按钮设置
    prev.addEventListener('click', function(){
      if(flag){
        flag = false;
          //无缝滚动原理:复制第一张图片放到最后;判断如果走到最后一张图,则ul的left复原为0
          if(num == 0){
            num = ul.children.length-1;
            ul.style.left = - num*bannerWidth + 'px';
        }
        num--;
        animate(ul, - num*bannerWidth, function(){
            flag = true;
        });
    // 点击左侧按钮,小圆圈也跟随变化,可以声明一个变量circle
        circle--;
        // 如果circle小于0,说明小圆圈选中状态跳到最后一张上
        // if(circle < 0){
        //     circle =pointer.children.length-1;
        // }
        circle = circle<0? pointer.children.length-1 : circle;
        circleChange();
        
      }
    })
    function circleChange(){
        // 先清除其他小圆圈的样式
        for(var i = 0; i<pointer.children.length; i++){
            pointer.children[i].className = '';
        }
        // 留下当前小圆圈的current
        pointer.children[circle].className = 'current';
    }

    // 10.自动播放轮播图
    var timer = setInterval(function(){
        // 手动调用事件
        next.click();
    },3000)



})

你可能感兴趣的:(JavaScript初级,【前端学习笔记】,前端,javascript,html)