原生js轮播图
2018-10-19 06:14:00来源:博客园 阅读 ()
前言
轮播图在前端中的应用场景非常多、应用频率非常高,大到网站商城,小到个人主页,都会有用到轮播图的时候。
现在网上的轮播图插件也非常多,花样花式也各异,有基于jq的、基于框架,所以一般是不用我们去手写轮播图的。
但在某些情况下,我们还是需要去手写轮播图。
手写原生js轮播图,有助于我们知道轮播图的实现原理。
知道了原理,有时候我们也能根据自己的需求去修改下载下来插件的源码。
效果
我们先来看下轮播图的最终效果图:
根据上面的效果图,我们来总结一下我们要实现的轮播图的功能:
- 箭头点击
- 按钮点击
- 滑动过渡
- 自动播放
原理
轮播图的原理要配合html结构和css样式来讲。
我们先来看一下html结构:
<div class="slide-wrapper" id="slide_wrapper"> <div class="slide-imgs" id="slide_imgs" style="left: -400px;"> <img class="slide-img" src="slide-img3.jpg"><!-- 辅助过渡图 --> <img class="slide-img" src="slide-img0.jpg"> <img class="slide-img" src="slide-img1.jpg"> <img class="slide-img" src="slide-img2.jpg"> <img class="slide-img" src="slide-img3.jpg"> <img class="slide-img" src="slide-img0.jpg"><!-- 辅助过渡图 --> </div> <div class="slide-btns" id="slide_btns"> <span class="slide-btn active" data-index="0"></span> <span class="slide-btn" data-index="1"></span> <span class="slide-btn" data-index="2"></span> <span class="slide-btn" data-index="3"></span> </div> <a class="slide-arrow" id="slide_left" href="#"><</a> <a class="slide-arrow" id="slide_right" href="#">></a> </div>
上图是我们整个轮播图的html结构,可以看出代码是很少的。
可以看到,我实现的轮播图用了4张图片,但代码中有6张,我用代码注释标记的2张图片是辅助图,用来辅助动画过渡,下面会讲到。
请注意观察 slide-wrapper 和 slide-imgs 。
另外可以发现 class="slide-imgs" 元素上有样式属性 left ,在html里写样式是为了方便我们待会在js中取该元素的 left 的值。
接下来我们配合在浏览器里的效果(按F12打开控制台)来讲解轮播图的原理:
从图片中可以看出,我们轮播图每张图片的宽度是400px,同样的,整个轮播图容器 .slide-wrapper 的宽度也是 400px,当然高度也是一样。
上面的图片是 .slide-imgs 元素,它是包裹我们所有图片的容器,它的宽度是2400px,这是因为我们有6张图片,每张图片是400px(上图因为太长我没有截出)。
接着就是设置 .slide-wrapper 元素的样式,将轮播图最外层的包裹元素 overflow: hidden; :
.slide-wrapper { position: relative; width: 400px; height: 250px; overflow: hidden; }
轮播图的原理就是让“包裹图片的容器元素”(.slide-imgs元素)做位置偏移。
每次偏移的距离是每张图片的宽度。
每次切换的时候,我们就重新改变 .slide-imgs元素 的样式属性 left 的值(将.slide-wrapper设置为相对定位,将.slide-imgs设置为绝对定位)。
从上图就可以看到所有图片的包裹元素进行了位置偏移,这就是轮播图的核心原理了。
箭头点击
var slide_left = document.getElementById('slide_left'), slide_right = document.getElementById('slide_right'), slide_imgs = document.getElementById('slide_imgs'),
slide_left.onclick = function() { ... imgChange(400); ... }; slide_right.onclick = function() { ... imgChange(-400); ... };
首先获取我们两个箭头按钮的元素,编写点击后要执行的代码,
每一次点击,就切换一张图片,切换的大小是图片的宽度,这里是400px。
左点击就传入负值,右点击就传入正值,然后执行图片切换的函数 imgChange() :
function imgChange(offset) { var newLeft = parseInt(slide_imgs.style.left) + offset, // 新坐标值 ... slide_imgs.style.left = newLeft + 'px'; if (newLeft > -400) { slide_imgs.style.left = -1600 + 'px'; } if (newLeft < -1600) { slide_imgs.style.left = -400 + 'px'; } ... }
imgChange()函数的作用是:
利用的传入的偏移值,计算出 .slide-imgs元素 该具有的新的位置值(left值),值计算出来后,再设置 . slide-imgs元素 的样式属性。
当向左切换,切换超出第一张图片的时候,将 .slide-imgs元素 的位置赋值为最后第四张图片的位置值;
当向右切换,切换超出第四张图片的时候,将 .slide-imgs元素 的位置赋值为最后第一张图片的位置值(如上面的if语句),这样就能实现循环切换。
按钮点击
当点击按钮的时候我们要做两件事情:
1.切换到对应的图片;
2.改变按钮的样式。
要做到这两件事我们就需要一个值 slide_index 来记住当前图片和圆点的位置索引:
<div class="slide-btns" id="slide_btns"> <span class="slide-btn active" data-index="0"></span> <span class="slide-btn" data-index="1"></span> <span class="slide-btn" data-index="2"></span> <span class="slide-btn" data-index="3"></span> </div>
slide_btns = document.getElementById('slide_btns').getElementsByTagName('span'), slide_wrapper = document.getElementById('slide_wrapper'), slide_index = 0, // 当前图片或圆点的索引
for (var i=0; i<slide_btns.length; i++) { slide_btns[i].onclick = function() { ... var data_index = parseInt(this.getAttribute('data-index')); var offset = -400 * (data_index - slide_index); ... imgChange(offset); slide_index = data_index; btnChange(); }; }
我们先完成第一件事:切换到对应的图片。
从html代码可以看出,我们给每一个按钮都赋予了相应的位置索引值 data-index。
接着,我们再给每一个按钮添加点击事件,当点击按钮的时候,我们再调用imgChange()函数,并传入正确的偏移量的值。
因为点击按钮的时候是可以跳跃性地点击,比如点第一个按钮后点第二个按钮,但也可以点第一个按钮后就点第四个按钮,
所以传入的偏移量通过这句代码来计算:
// data_index是点击的按钮的位置索引
// slide_index是当前图片的位置索引
var offset = -400 * (data_index - slide_index);
所以当我们执行imgChange()函数后要记得更新当前图片的索引值:
slide_index = data_index;
最后是完成第二件事:改变按钮的样式:
function btnChange() { for (var i=0; i<slide_btns.length; i++) { if (slide_btns[i].className = 'slide-btn active') { slide_btns[i].className = 'slide-btn'; } } slide_btns[slide_index].className = 'slide-btn active'; }
分析一下上面的代码,事先将选中按钮的样式 .active 写好:
.active { background-color: #20217e; }
再改变选中按钮的类名(className),赋予它 active :
slide_btns[slide_index].className = 'slide-btn active';
前提,我们要先利用循环清除每一个按钮的 .active ,这样才不会出现多个选中按钮:
for (var i=0; i<slide_btns.length; i++) { if (slide_btns[i].className = 'slide-btn active') { slide_btns[i].className = 'slide-btn'; } }
滑动过渡
上面我们所实现都效果都是一瞬间的,就是一瞬间就切换到下一张图片,并没有一种过渡的视觉体验。
如何实现这种滑动过渡的效果?
我们知道,轮播图的核心原理是位置偏移,就是从一个位置到另一个位置的改变,
如果我们为这种改变加上一段时间,假设这个时间是2s,那么完成这个变化就得花2s时间,就不是一瞬间完成了,
这个完成过程就是过渡,这个过渡因为时间够长,所以能被我们所观察到。
好了,现在我们有一段时间 time 了,但还不够,
因为滑动的实质是慢慢地偏移,将一段完整的偏移量分为几次小的偏移量,
假设我们的 time = 500ms,我们每一次所花时间 perTime = 10ms,
所以在500ms内,我们要偏移多少次 per = time / perTime ,
每一次偏移的距离为 perOffset = offset / per 。
一直地偏移,如果还没到达偏移的目标量时,还是继续偏移,
这里我们用一个延时定时器和递归来达到这个效果,每 10ms 就进行一次偏移:
function imgChange(offset) { var newLeft = parseInt(slide_imgs.style.left) + offset, // 新坐标值 time = 500, // 总移动时间 perTime = 10, // 每次移动的时间 per = time / perTime, // 移动多少次 perOffset = offset / per; // 每次移动的距离 animate = function() { animated = true; // 注意这里的parseInt(slide_imgs.style.left)是一个实时的值,不能赋给一个变量以节省代码 if ((perOffset < 0 && parseInt(slide_imgs.style.left) > newLeft) || (perOffset > 0 && parseInt(slide_imgs.style.left) < newLeft)) { slide_imgs.style.left = parseInt(slide_imgs.style.left) + perOffset + 'px'; setTimeout(animate, perTime); } else { animated = false; slide_imgs.style.left = newLeft + 'px'; if (newLeft > -400) { slide_imgs.style.left = -1600 + 'px'; } if (newLeft < -1600) { slide_imgs.style.left = -400 + 'px'; } } }; animate(); }
两张辅助图
如果没有设置辅助图做衔接的话,假设从第四张图滑向第一张图,第四张图会先滑向一片空白区域:
而不是
自动播放
用一个定时器自动地去调用箭头点击函数:
function autoPlay() { timer = setInterval(function() { slide_right.onclick(); }, 2000); } ... autoPlay(); // 在结尾的时候调用自动播放函数
源码
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>原生js轮播图</title> <style> .slide-wrapper { position: relative; width: 400px; height: 250px; overflow: hidden; } .slide-imgs { position: absolute; z-index: 1; width: 2400px; height: 250px; } .slide-img { float: left; width: 400px; height: 250px; } .slide-btns { position: absolute; right: 0; bottom: 5px; left: 0; z-index: 2; width: 60px; margin: auto; } .slide-btn { display: inline-block; float: left; width: 10px; height: 10px; margin: 0 2px; background-color: #fff; border-radius: 50%; cursor: pointer; } .active { background-color: #20217e; } .slide-arrow { position: absolute; top: 0; bottom: 0; z-index: 2; width: 23px; height: 23px; margin: auto; color: #fff; font-size: 30px; font-weight: bold; line-height: 23px; text-decoration: none; } #slide_left { left: 5px; } #slide_right { right: 5px; } </style> </head> <body> <div class="slide-wrapper" id="slide_wrapper"> <div class="slide-imgs" id="slide_imgs" style="left: -400px;"> <img class="slide-img" src="slide-img3.jpg"><!-- 辅助过渡图 --> <img class="slide-img" src="slide-img0.jpg"> <img class="slide-img" src="slide-img1.jpg"> <img class="slide-img" src="slide-img2.jpg"> <img class="slide-img" src="slide-img3.jpg"> <img class="slide-img" src="slide-img0.jpg"><!-- 辅助过渡图 --> </div> <div class="slide-btns" id="slide_btns"> <span class="slide-btn active" data-index="0"></span> <span class="slide-btn" data-index="1"></span> <span class="slide-btn" data-index="2"></span> <span class="slide-btn" data-index="3"></span> </div> <a class="slide-arrow" id="slide_left" href="#"><</a> <a class="slide-arrow" id="slide_right" href="#">></a> </div> <script> var slide_left = document.getElementById('slide_left'), slide_right = document.getElementById('slide_right'), slide_imgs = document.getElementById('slide_imgs'), slide_btns = document.getElementById('slide_btns').getElementsByTagName('span'), slide_wrapper = document.getElementById('slide_wrapper'), slide_index = 0, // 当前图片或圆点的索引 animated = false, // 标记是否处于动画状态 timer = null; function imgChange(offset) { var newLeft = parseInt(slide_imgs.style.left) + offset, // 新坐标值 time = 500, // 总移动时间 perTime = 10, // 每次移动的时间 per = time / perTime, // 移动多少次 perOffset = offset / per; // 每次移动的距离 animate = function() { animated = true; // 注意这里的parseInt(slide_imgs.style.left)是一个实时的值,不能赋给一个变量以节省代码 if ((perOffset < 0 && parseInt(slide_imgs.style.left) > newLeft) || (perOffset > 0 && parseInt(slide_imgs.style.left) < newLeft)) { slide_imgs.style.left = parseInt(slide_imgs.style.left) + perOffset + 'px'; setTimeout(animate, perTime); } else { animated = false; slide_imgs.style.left = newLeft + 'px'; if (newLeft > -400) { slide_imgs.style.left = -1600 + 'px'; } if (newLeft < -1600) { slide_imgs.style.left = -400 + 'px'; } } }; animate(); } function btnChange() { for (var i=0; i<slide_btns.length; i++) { if (slide_btns[i].className = 'slide-btn active') { slide_btns[i].className = 'slide-btn'; } } slide_btns[slide_index].className = 'slide-btn active'; } function autoPlay() { timer = setInterval(function() { slide_right.onclick(); }, 2000); } function stopPlay() { clearInterval(timer); } slide_left.onclick = function() { if (!animated) { // 防止快速点击后出现BUG imgChange(400); if (slide_index == 0) { slide_index = 3; } else { slide_index -= 1; } btnChange(); } }; slide_right.onclick = function() { if (!animated) { imgChange(-400); if (slide_index == 3) { slide_index = 0; } else { slide_index += 1; } btnChange(); } }; for (var i=0; i<slide_btns.length; i++) { slide_btns[i].onclick = function() { if (this.className != 'slide-btn active') { var data_index = parseInt(this.getAttribute('data-index')); var offset = -400 * (data_index - slide_index); if (!animated) { imgChange(offset); slide_index = data_index; btnChange(); } } }; } slide_wrapper.onmouseover = stopPlay; slide_wrapper.onmouseout = autoPlay; autoPlay(); </script> </body> </html>
参考视频:https://www.imooc.com/learn/18
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- jsTree树插件 2019-08-14
- JavaScript轮播图 2019-08-14
- 原生js实现图片懒加载+加入节流 2019-08-14
- 用原生JS写省市二级联动 2019-08-14
- 使用原生node.js搭建HTTP服务器,支持MP4视频、图片传输,支 2019-08-14
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash