前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!

目录

前言

 一、结构搭建

细节部分:

代码实现:

效果图:

二、功能模块分析

1、盒子模块

原理:

代码实现:

效果:

2、焦点模块(重点)

原理:

细节部分:

代码实现:

效果:

3、右侧按钮模块(重点)

原理:

细节部分:

代码实现:

 效果:

4、左侧按钮

原理:

细节部分:

代码实现:

效果:

5、自动播放模块

原理:

代码实现:

效果:

6、节流阀模块

原理:

细节部分:

代码实现:

 7、一些会碰到的疑问

1、为什么焦点数小于实际的图片数?

2、克隆不成功

3、图片不移动

三、完整代码

 效果图:

四、结束语


前言


       在此之前,小糖其实尝试了很多讲解方式,但还是不满意推翻重写(小糖写文章的风格初衷就是尽量简短精细易懂)琢磨了两天,甚至于在CSDN观摩其他人的轮播图讲解文章,还是感觉讲的太晦涩,最后决定用模块化的讲解方式,(也算另一种简短了吧?)
这样大家好接受一些,不会眼花缭乱。制作不易,这篇文章足够大家放收藏夹吃灰了吧哈哈哈哈哈哈......

 一、结构搭建

细节部分

1、要注意焦点数是与(展示的)图片数量同步的。
如下:原生HTML焦点列表中是没写焦点的    


     2、图片要用列表包裹,且一行显示(用浮动)时,会发现其他图片消失了
        (原因:只是让li左浮动,但是浮动的元素无法撑开ul,所以让ul变宽即可,如下)
     

    ul {
                position: absolute;
                width: 800%;
                height: 100%;
            }


     3、注意按钮层级!不然会被图片覆盖啦!要用按钮的css中的z-index!

    .arrow-l, .arrow-r {
                z-index: 999;
    }

    代码实现:


         

      * {
                padding: 0;margin: 0;
            }
            .focus {
                overflow: hidden;
                position: relative;
                margin: 100px auto;
                width: 520px;
                height: 280px;
                background-color: pink;
                border-radius: 10px;
            }
            ul {
                position: absolute;
                width: 800%;
                height: 100%;
            }
            ul li {
                list-style: none;
                float: left;
                
            }
            .arrow-l, .arrow-r {
                display: none;
                text-decoration: none;
                z-index: 999;
                position: absolute;
                top:50%;
                margin-top: -20px;
                width: 24px;
                height: 40px;
                color:#fff;
                line-height: 40px;
                font-size: 18px;
                background: rgba(121, 120, 120, 0.5);
                text-align: center;
                border-radius: 0 9px 9px 0;
            }
            .arrow-l:hover, .arrow-r:hover {
                color:orange;
                font-weight: bolder;
            }
            .arrow-r {
                right: 0;
                border-radius: 9px 0 0 9px;
            }
            ol {
                position: absolute;
                bottom: 10px;
                left: 10px;
                display: flex;
                justify-content: space-evenly;
    
            }
            ol li {
                list-style: none;
                margin-right: 2px;
                width: 10px;
                height: 10px;
                background-color: rgb(255, 255, 255);
                border-radius: 50%;
                cursor: pointer;
                border: 1.5px solid white;
            }
            .carrent {
                background-color: orange;
            }
     
                    <         >                
                 
    •                            
    •            
    •                            
    •            
    •                            
    •            
    •                            
    •                     
                   
         

      效果图:

      前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!_第1张图片

      二、功能模块分析

      1、盒子模块


      原理:

                         当鼠标进入盒子时显示按钮,离开时隐藏按钮
                       (小糖觉得也可以用css平替,不过后期应该不行叭~)

      代码实现:

      var focus1 = document.querySelector('.focus');
              var arrowl = document.querySelector('.arrow-l');
              var arrowr = document.querySelector('.arrow-r');
              focus1.addEventListener('mouseenter',function(){
                  arrowl.style.display = 'inline-block';
                  arrowr.style.display = 'inline-block';
              });
              focus1.addEventListener('mouseleave',function(){
                  arrowl.style.display = 'none';
                  arrowr.style.display = 'none';
              });


      效果:

      前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!_第2张图片

      2、焦点模块(重点)

      原理:

                         利用js-DOM 根据(展示的)图片数量创建焦点,且当焦点被点击时变色图片切换

      细节部分:

                   1、利用之前我们书写缓动效果时的函数,把它封装起来,现在可以用来修改啦
                   2、在创建焦点时要记录它的索引号,后面可以根据索引号找图片
                         记录后也要声明再使用哦!!
                   3、盒子宽度要声明为全局变量(focus1width)
                   4、图片移动的距离就是:- 索引号 * 盒子宽度(focus1width) 

      代码实现:

       var ul = focus1.querySelector('ul');
              var ol = focus1.querySelector('.circle');
              for(var i = 0;i < ul.children.length;i++){
                  //创建新元素
                  var li = document.createElement('li');
                  //记录当前小圆圈的索引号 用自定义属性来做
                  li.setAttribute('index',i);
                  //将元素插入ol里面
                  ol.appendChild(li);
      
              li.addEventListener('click',function(){   //排他思想一定写在循环里面 不然只能执行一次
                  for(var i = 0;i < ol.children.length;i++){
                      //排除所有
                      ol.children[i].className = '';
                  }
                  //留下自己
                  this.className = 'carrent';
                  //ul移动的距离 小圆圈的索引号 乘以 图片的宽度 
                  //当我们点击某个li 就拿到当前li的索引号 
                  var index = this.getAttribute('index');
                  //var focus1width = focus1.offsetWidth;   要改为全局变量
                  animate(ul,-index * focus1width);
              });
              };

      效果:
       

      3、右侧按钮模块(重点)


      原理:

                         点击按钮实现图片切换,用一个num变量控制图片切换;实现无缝滚动效果

      细节部分:

                   1、无缝滚动:将ul中的第一个li复制一份放到ul最后面(即用深克隆
                         当图片滚动到最后一张时,让ul快速跳到最左侧, left:0; 同时赋值num为0。
                   2、还要在声明一个circle变量控制焦点播放
                   3、可能出现circle与num不一致造成bug,解决办法:在焦点的事件侦听器中令两者与索引号一致。
                   4、知道无缝滚动时,num是如何变化的(细看代码)

      代码实现:

      var num = 0;    //控制图片切换           
              var circle = 0;    //控制焦点播放     
              arrowr.addEventListener('click',function(){
                      if(num == ul.children.length - 1) {
                      ul.style.left = 0 + 'px';
                      num = 0;
                  }
                  num++;     
                  animate(ul,-num*focus1width);
                  circle++;
                  //但是图片有五张 源泉只有四个,所以要设置
                  if(circle == ol.children.length) {
                      circle = 0;
                  };               //要放在排他思想之前 因为if是执行的前提
                  
                  //排他思想
                  //先清除其余小圆圈的current类名
                  for (var i = 0;i < ol.children.length;i++){
                      ol.children[i].className = '';
                  }
                  //留下当前小圆圈的类名
                  ol.children[circle].className = 'carrent';
              }
              });

       效果:

       

      4、左侧按钮


      原理:

                         同上

      细节部分:

                   注意修改无缝滚动的条件以及焦点播放的条件

      代码实现:

      arrowl.addEventListener('click',function(){
                      if(num == 0) {
                      num = ul.children.length - 1;
                      ul.style.left = -(num*focus1width) + 'px';
                  }
                  num--;     
                  animate(ul,-num*focus1width);
      
                  //点击左侧按钮 小圆圈跟着变化 可以再声明一个变量控制小圆圈的播放
                  circle--;
      
                  //但是图片有五张 圆圈只有四个,所以要设置
                  if(circle < 0) {
                      circle = ol.children.length - 1;
                  }; //要放在排他思想之前 因为if是执行的前提
      
                  //排他思想
                  //先清除其余小圆圈的current类名
                  for (var i = 0 ; i < ol.children.length ; i++){
                      ol.children[i].className = '';
                  }
                  //留下当前小圆圈的类名
                  ol.children[circle].className = 'carrent';
                  }
                  
              });


      效果:
       

      5、自动播放模块

      原理:

                        利用定时器实现图片切换,可利用右侧按钮的”手动调用事件“

      代码实现:

       //自动播放 
              var timer = setInterval(function(){
                  arrowr.click();   //手动调用事件
              },2000);

      效果:
       

      6、节流阀模块

      原理:

                        相当于给每次图片切换加一个”开关“,当切换完成才可以打开,

                        而判断是否完成切换的重要侦听器就是利用回调函数callback。

      细节部分:

                        callback是加在每个按钮侦听器里的,要声明一个布尔类型的变量充当开关

      代码实现:
       

      前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!_第3张图片

       (左右侧按钮同样道理,此处只展示右侧)

       7、一些会碰到的疑问

      1、为什么焦点数小于实际的图片数?

            答:因为我们是优先获取焦点,再额外克隆第一张图片,按照事件流执行顺序,焦点数已是完成获取的了。

      2、克隆不成功

            答:克隆要使用深克隆,值为true

      3、图片不移动

            答:移动的是整个ul而不是单个li

      三、完整代码

      最后给盒子添加溢出隐藏就好啦~
      完整js代码自取!

       //1.获取按钮
              var focus1 = document.querySelector('.focus');
              var arrowl = document.querySelector('.arrow-l');
              var arrowr = document.querySelector('.arrow-r');
              var focus1width = focus1.offsetWidth;      //要改成全局变量
              var flag = true;  //节流阀
              focus1.addEventListener('mouseenter',function(){
                  arrowl.style.display = 'inline-block';
                  arrowr.style.display = 'inline-block';
                  clearInterval(timer) ;  //当鼠标进入,停止自动播放
                  timer = null;
              });
              focus1.addEventListener('mouseleave',function(){
                  arrowl.style.display = 'none';
                  arrowr.style.display = 'none';
                  timer = setInterval(function(){
                  arrowr.click();   //手动调用事件
              },2000);
              });
              //3.动态生成小圆圈 几个图片 几个小圆圈
              var ul = focus1.querySelector('ul');
              var ol = focus1.querySelector('.circle');
              for(var i = 0;i < ul.children.length;i++){
                  //创建新元素
                  var li = document.createElement('li');
                  //记录当前小圆圈的索引号 用自定义属性来做
                  li.setAttribute('index',i);
                  //将元素插入ol里面
                  ol.appendChild(li);
                  li.addEventListener('click',function(){   //排他思想一定写在循环里面 不然只能执行一次
                  for(var i = 0;i < ol.children.length;i++){
                      //排除所有
                      ol.children[i].className = '';
                  }
                  //留下自己
                  this.className = 'carrent';
                  //5.点击小圆圈 ul移动
                  //ul移动的距离 小圆圈的索引号 乘以 图片的宽度 
                  //当我们点击某个li 就拿到当前li的索引号 
                  var index = this.getAttribute('index');
                  num = circle = index;      //num 和 circle 和索引号统一 才不会出现bug
      
                  //var focus1width = focus1.offsetWidth;   要改为全局变量
                  animate(ul,-index * focus1width);
              });
              };
      
              //6.克隆第一张图片
              var first = ul.children[0].cloneNode(true);
              ul.appendChild(first);
      
      
              //右侧按钮    无缝滚动原理:将ul中的第一个li复制一份放到ul最后面
              //            当图片滚动到最后一张时,让ul快速跳到最左侧 即 left:0; 同时赋值num为0
              var num = 0;    //控制图片切换           
              var circle = 0;    //控制焦点播放     
              arrowr.addEventListener('click',function(){
                  if(flag) {
                      flag = false;
                      if(num == ul.children.length - 1) {
                      ul.style.left = 0 + 'px';
                      num = 0;
                  }
                  num++;     
                  animate(ul,-num*focus1width,function(){
                      flag = true;
                  });
      
                  //点击右侧按钮 小圆圈跟着变化 可以再声明一个变量控制小圆圈的播放
                  circle++;
      
                  //但是图片有五张 源泉只有四个,所以要设置
                  if(circle == ol.children.length) {
                      circle = 0;
                  };               //要放在排他思想之前 因为if是执行的前提
                  
      
                  //排他思想
                  //先清除其余小圆圈的current类名
                  for (var i = 0;i < ol.children.length;i++){
                      ol.children[i].className = '';
                  }
                  //留下当前小圆圈的类名
                  ol.children[circle].className = 'carrent';
              }
              });
              //9.左侧按钮
              arrowl.addEventListener('click',function(){
                  if(flag) {
                      flag = false;
                      if(num == 0) {
                      num = ul.children.length - 1;
                      ul.style.left = -(num*focus1width) + 'px';
                  }
                  num--;     
                  animate(ul,-num*focus1width,function(){
                      flag = true;
                  });
      
                  //10.点击左侧按钮 小圆圈跟着变化 可以再声明一个变量控制小圆圈的播放
                  circle--;
      
                  //但是图片有五张 圆圈只有四个,所以要设置
                  if(circle < 0) {
                      circle = ol.children.length - 1;
                  }; //要放在排他思想之前 因为if是执行的前提
      
                  //排他思想
                  //先清除其余小圆圈的current类名
                  for (var i = 0 ; i < ol.children.length ; i++){
                      ol.children[i].className = '';
                  }
                  //留下当前小圆圈的类名
                  ol.children[circle].className = 'carrent';
                  }
                  
              });
              //11.自动播放 
              var timer = setInterval(function(){
                  arrowr.click();   //手动调用事件
              },4000);
      
              function animate(obj,target,callback){
              clearInterval(obj.timer);
               obj.timer = setInterval(function(){
                  //步数加在计时器里
                  var step = (target - obj.offsetLeft)/10;
                  step = step > 0? Math.ceil(step) : Math.floor(step);   
                  //解决在前进与后退两种情况下 step 应该  “向上取整”  还是  “向下取整”!!!!!!!
          
          
                   //当不断点击按钮时,这个元素就会越来越快,因为启动了太多计时器
                   //解决办法:在启动定时器时之前保证只有一个计时器 即先清除所有计时器
              if( obj.offsetLeft == target){  //用  “==”   取代  '>='  可以解决盒子返回时无法执行的问题
                  clearInterval(obj.timer);
                  if(callback) {
                      callback();
                  }
              }
              obj.style.left = obj.offsetLeft + step +'px';
          },20);
          };

       效果图:

      四、结束语

      希望本篇文章可以帮到求知若渴的众多同学吖~
      若能帮到 也欢迎点赞、收藏、关注我,后续也会持续发布新文章,祝大家学有所成!
      欢迎各位前端大佬留言讨论指教!
       小糖谢谢各位啦~❤  ❤  ❤  ❤

      你可能感兴趣的:(前端,javascript,css,html)