什么是轮播图?
轮播图,图片旋转器,滑片,无论你怎么叫这玩意,它在网络上无处不在。轮播图在电商网站主页上广泛应用,大多数电商网站的主页上都有它:
本轮播图Demo
喏~两个链接甩给泥萌
Github仓库文件
在线Demo(移动端加载很慢)
前言
网上有很多的轮播图特效,部分采用的transition属性结合JS实现滚动,但是很遗憾没有无缝效果,什么是无缝?我给前端小白画了一个示意图。另外本文是我写的第一篇文章,难免有生疏之处。包含很多知识点回顾,很适合JS新手学习。
当焦点位于图片1时,如果再往前滚的话,整个队列会被拉倒真正的第五张图。至于真正的图片1前面的副本图片5只是让用户产生视觉差,从而不会让用户明显感觉到图片被倒向了图片5,看起来就像时无缝轮播。
同理当焦点位于图片5时,如果再往后滚,道理同上不再赘述。
实现功能
1.当鼠标放入容器内时左右出现控制按钮,并且轮播动画停止。
2.当鼠标移出时,控制按钮隐藏,轮播继续。
3.焦点随图片的滚动而变化。
4.跳跃点击焦点,会跳转到相应的图片。
5.以及前沿所述的无缝轮播。
开搞~~
Html代码:
(内有注释解析)
<div id="container">
<div id="list" style="left: -600px;">//初始状态是真正的图片1,也就是绝对定位-600px
![](img/555.jpg)
![](img/111.jpg)
![](img/222.jpg)
![](img/333.jpg)
![](img/444.jpg)
![](img/555.jpg)
![](img/111.jpg)
</div>
<div id="buttons">
<span index="1" class="on"></span>//动画开始时小圆点位于第一个
<span index="2"></span>
<span index="3"></span>
<span index="4"></span>
<span index="5"></span>
</div>
<a id="prev" class="arrow"><</a>//前一个箭头
<a id="next" class="arrow">></a>//后一个箭头
</div>
开始讲解代码:
1.箭头控制
var prev=document.getElementById("prev");
var next=document.getElementById("next");
var list=document.getElementById("list");
prev.onclick=function(){
list.style.left=parseInt(list.style.left)-600+"px";
}
next.onclick=function(){
list.style.left=parseInt(list.style.left)+600+"px";
}
给a标签绑定点击事件,先获取list
的left
属性并且取出数字进行运算操作。下面我们来做一些优化,把定义一个function animate()
函数,传入offset
参数,并把var newLeft=parseInt(list.style.left) +offset;
,然后让prev
和next
的点击事件调用这个函数。
function animate(offset){
list.style.left=newLeft+offset+"px";
}
prev.onclick=function(){
animate(-600);
}
next.onclick=function(){
animate(600);
}
然后我们会发现当我们点击到第五张图片left=-3000px
时,它应该滚到真正的第1张而不是副本1。我们可以像下面这样写实现无缝滚动:
function animate(offset){
list.style.left=newLeft+offset+"px";
if (newLeft >-600) {
list.style.left=-3000+"px";
};
if (newLeft <-3000) {
list.style.left=-600+"px";
};
}
用箭头控制图片的轮播大工告成!!(撒花~)
2.焦点跟随
这个功能可能比较难以理解,其实和第一部分是一样的。首先考虑到prev和next点击事件中要有标记,这个标记就是一个挂钩,再定义一个函数利用这个挂钩来跟随焦点。我们用showButton()
函数,全局定义变量var index=1
先让第一幅图的焦点亮起来。下面我们来看代码(忽略animate
变量,下一部分我们会讲到):
var buttons=document.getElementById("buttons").getElementsByTagName("span");
var index=1//buttons[0].classNme="on";
var animated=false;//全局动画停止标记
function shownButton(){
/* for循环的作用就是当prev和next每click一次,
就会清除一次前一个class为on的span元素*/
for (var i = 0; i < buttons.length ; i++) {
buttons[i].className="";
}
buttons[index -1].className="on";//焦点跟随
}
prev.onclick=function(){
if (!animated) {//这里判断
if (index==1) {
/*这就是我们下面要讲到的当焦点位于第一个span时,让它跳转到第5个*/
index=5;
}else {
index -=1;
}
shownButton();//把上一个亮起的灭掉,下一个亮起
animate(600);
}
};
next.onclick=function(){
if (!animated) {/*全局变量animated=false,那么!animated=true
if (index==5) {
index=1;
}else {
index +=1;
}
shownButton();
animate(-600);
}
};
3.焦点轮播(实现功能第四点)
当图片位于第一个焦点时,我点击第四的焦点。left=-600px
变成了left=-2400px
话不多说,来看下面的代码吧。
for (var i = 0; i < buttons.length; i++) {
buttons[i].onclick=function(){
//无关紧要,性能优化使用,目的是当index和myindex相等时,退出函数
if (this.className=="on") {
return;
}
var myIndex=parseInt(this.getAttribute("index"));//index不是a的固有属性,因此要用dom调用
var offset=-600*(myIndex-index);
if (!animated) {/*又出现了这个animated,
在此意思是如果animate()执行过程中,animated=true,那么animate()不能再次被 调用*/
animate(offset);
}
index=myIndex;//更新index,便于下一次的轮播
shownButton();
}
}
4.动画函数
动画函数go()
整合到了animate()
函数里了。只可意会不可言传(手动滑稽)直接上代码吧:
function animate(offset){
var speed = offset/30;//每次的位移,分母越大越流畅
animated=true;//动画正在运行,别的事件不要来打扰
var newLeft=parseInt(list.style.left) +offset;
function go(){
if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) > newLeft)) {
list.style.left = parseInt(list.style.left) + speed + 'px';
setTimeout(go, inteval);//递归函数
}
else
{
animated=false;
list.style.left=newLeft+"px";
if (newLeft >-600) {
list.style.left=-3000+"px";
};
if (newLeft <-3000) {
list.style.left=-600+"px";
};
}
}
go();
};
5.定时器
var container=document.getElementById("container");
var timer;
function play(){
timer=setInterval(function(){
next.onclick();
},2000);
}
function stop(){
clearInterval(timer);
}
play();
container.onmouseover=stop;
container.onmouseout=play;
最后放一遍总的JS代码
高大上的JS代码(滑稽)
< script >
window.onload = function ()
{
var prev = document.getElementById("prev");
var next = document.getElementById("next");
var list = document.getElementById("list");
var buttons = document.getElementById("buttons").getElementsByTagName("span");
var container = document.getElementById("container");
var index = 1;
var timer;
var animated = false;
function shownButton()
{
for (var i = 0; i < buttons.length ; i++)
{
if ( buttons[i].className == 'on')
{
buttons[i].className = '';
/* prev和next每click一次,
就会清除一次前一个class为on的span元素,
所以没有必要再去循环下面的span*/
break;
}
// 或者直接遍历清除 buttons[i].className="";
}
buttons[index - 1].className = "on";
}
function animate(offset)
{
var time = 300;
var inteval = 10;
var speed = offset / (time / inteval);
animated = true;//更改全局变量,防止跳图
var newLeft = parseInt(list.style.left) + offset;
function go()
{
if ( (speed > 0 && parseInt(list.style.left) < newLeft) || (speed < 0 && parseInt(list.style.left) > newLeft)) {
list.style.left = parseInt(list.style.left) + speed + 'px';
setTimeout(go, inteval);
}
else
{
animated = false;//全局变量
list.style.left=newLeft+"px";
if (newLeft > -600) {
list.style.left =- 3000 + "px";
};
if (newLeft <- 3000) {
list.style.left =- 600 + "px";
};
}
}
go();
};
prev.onclick = function ()
{
/*添加一个if判断index为1时,如果继续往前滚的话就让index返回第五个span
但是当快速点击arrow时会出现一种span点亮延迟的情况。可以尝试把判断index是否大于1或小于5的情况放进
判断是否animated的if语句中,先判断能不能点击,再点亮。
*/
if (!animated) {
if (index == 1) {
index = 5;
}
else {
index -= 1;
}
shownButton();
animate(600);
}
};
next.onclick = function ()
{
if (!animated) {
if (index == 5) {
index = 1;
}
else {
index += 1;
}
shownButton();
animate(-600);
}
};
for (var i = 0; i < buttons.length; i++)
{
buttons[i].onclick = function ()
{
//无关紧要
if (this.className == "on") {
return;
}
var myIndex = parseInt(this.getAttribute("index"));
var offset =- 600 * (myIndex - index);
if (!animated) {
animate(offset);
}
index = myIndex;
shownButton();
}
}
function play()
{
timer = setInterval(function ()
{
next.onclick();
}, 2000);
}
function stop()
{
clearInterval(timer);
}
play();
container.onmouseover = stop;
container.onmouseout = play;
}
</script>
总结
其实写这种技术性文章最能考验你是否理解了这个特效,同时也是最累的。昨天晚上我在跟着慕课网做的时候,有一瞬间想放弃了,毕竟现在框架那么多,何必那么绞尽脑汁用一个复杂的函数做动画呢,直接引用JS库多省事。但是直到我写完这篇教程,我很庆幸我坚持下来了。这是我的第一篇文章,简书提供了一个很棒的平台来记录一个平凡人的世界。以后会常来这里,分享自己的所得,这也是一种喜悦。