前端|前端-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网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!
      文章图片
    • 前端|前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!
      文章图片
    • 前端|前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!
      文章图片
    • 前端|前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!
      文章图片

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


      二、功能模块分析 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、焦点模块(重点) 原理:
      利用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、左侧按钮
      原理:
      同上
      细节部分:
      【前端|前端-js网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!】注意修改无缝滚动的条件以及焦点播放的条件
      代码实现:
      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网页特效(终章)超详细的轮播图效果及原理 一篇彻底吃透!
      文章图片

      (左右侧按钮同样道理,此处只展示右侧)
      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); };


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









        推荐阅读