无缝轮播滚动图
效果图
实现效果
①无图片点击时,自动轮播设定定时器;
②点击圆点点会轮播并染色,点击左右键可轮播;
实现思路
①使图片整行排列,给一个窗口,溢出部分隐藏;
②因为要多次调用移动函数,经过尝试后选择参考封装一个animation.js函数,使其实现左右移动,透明度改变的效果;
③设定定时器进行轮播,注意的是设定的时间要大于一页滚动的时间;
④由于至今无法解决的问题,即快速多次点击按钮时因为当前页面因为还没滚动完,会实现鬼畜画面,最后选择的是将其锁定,让当前页面滚动完之后才能进行下一次点击滚动。无奈之举;
⑤无缝滚动想要实现的效果是第一张和最后一张进行无缝衔接,所以这里的思路是在第一张前面多放最后一张,后面同。
关于速度
实现变速:首先定义一个now让他获得我们要移动的元素的当前的位置的值,然后用我要要让他移动的距离即attr,去减去当前的位置,这个值会随着now的增大而减小。一开始没除以一个数,导致实现瞬移,因为now的初始值为0。
<!-- // <script> var box=document.getElementById("box");
box.onclick=function(){
animate(box,{left:500,top:300,opacity:150},function(){})}; -->
<!-- // 匀速运动
// setInterval(function(){
// var now=parseInt(getStyle(box,'left'));//获得它的id和属性,强制转化成整数
// box.style.left=now + 1 + "px";
// },30)
// var timer=setInterval(function(){
// var now=parseInt(getStyle(box,'left'));
// if(now==500){//当距离等于500时清除定时器
// clearInterval(timer)
// }
// else{
// box.style.left=now+1+"px";
// }
// },30);*/
// /*//变速运动,建立速度与当前目标值之间的关系
// var timer=setInterval(function(){
// var now=parseInt(getStyle(box,'left'));
// var speed=(500-now)/6;//这里如果不除一个数,一开始now==500,会出现瞬移,通过速度与当前位置的光系,可以体现一个速度越来越慢的效果
// speed=speed>0?Math.ceil(speed):Math.floor(speed);//取整
// console.log(now);//通过打印会发现由于前面除了一个数导致无法取整即无法到达指定位置,所以前面加一步取整
// if(now==500){
// clearInterval(timer)
// }else{
// box.style.left=now+speed+"px";
// }
// },30)
}
根据以上思路来封装一个animation函数
function getStyle(obj, attr){//考虑浏览器兼容
if(obj.currentStyle){
return obj.currentStyle[attr];
}
else{
return getComputedStyle(obj, null)[attr];//第二个参数为伪类此处无则写null
}
}
//运动的方向距离,以及透明度的变化
function animate(obj, json, callback){//对象,属性,回调函数(运动完后执行操作)
var timer = setInterval(function() {//按一定的周期执行此函数
var ifStop = true;//定义一个值来判断是否停止
var now = 0;//定义一个变量初始值为0
for (var attr in json){//遍历属性里面的所有值,可以对多个属性进行操作
if (attr == 'opacity') {//如果该属性是透明值
now = parseInt(getStyle(obj, attr));//强制转化成数字因为小数搞掉,所以那边输入的值要在一百以上
}
else {
now = parseInt(getStyle(obj,attr));//非透明值
}
var now = parseInt(getStyle(obj,attr));//获取obj和属性attr
var speed = (json[attr]-now)/4;
speed = speed>0? Math.ceil(speed):Math.floor(speed);//向上取整和向下取整
/*if(now==json[attr]){
clearInterval(timer)
}
else{*///这里的定时器不能直接清掉,因为json里面有多个属性,要判断是否每一个属性都达到
//无法判断是否每一个都到,但换个思路,我们可以判断只要有一个没到就不清除定时器
var current = now+speed;
if (attr == 'opacity'){
obj.style.opacity = current/100;// 这里记得给它除回去
}
else {
obj.style[attr] = current+"px";
if (json[attr] !== current){
ifStop = false;//只要有一个属性没有到达指定的位置,就设置成false,继续执行此函数
}
}
}
if (ifStop == true){//当确定所有的属性都执行完毕之后,清除定时器
clearInterval(timer);
if (callback){
callback()
};//如果存在返回函数,则执行返回函数
}
},100)
}
执行操作使其实现无缝滚动,即第三张和第一张进行一个自动的衔接
假设每张图的宽度为1200px;这里要注意的是当前我们看到的第一张它的序号为1,而它对应的小点点序号为0。这里写一个回调函数来判断是否当前的已经到达了第四张,当我们放到第四张的时候,重新把left设置成-1200px的这个时候它就回到了第一张,这个时候再重置一下index=1即可,当我们向左滑动时也是按照这个原理来实现,注意的是序号,以及应该移动的方向和距离1。
index=1;
index++;
NavChange();
animate(slider,{left: -1200*index},function(){//使用回调函数来判断是否为最后一张
if (index === 4){
slider.style.left= "-1200px";//判断成立时重新进行赋值
index = 1;
}
对于小圆点的移动
首先需要写的是一个清除和加点函数,独立写出来一个函数,最重要的一点就是注意它的序号是比图片少一的。然后调用我们的封装函数之前,我们要先把它的点点清除掉并且上色来实现。
//点击小原点到指定的地点
for (var i=0; i<Navlist.length; i++) {
Navlist[i].dex = i;
Navlist[i].onclick = function(){//这里的下标不需要锁定因为index只有几个固定的值
if (isMoving) {
return;
}
isMoving = true;
index = this.dex+1;
NavChange();
animate(slider, {left:-1200*index}, function(){isMoving=false;});
}
}
//小圆点颜色变化
function NavChange(){
for (var i=0; i<Navlist.length; i++) {//暴力清除所有点点颜色
Navlist[i].className = '';
}
if (index===4) { //到达最后一张图(第一张的时候),重新给第一个点点上色
Navlist[0].className = 'active';
}
else if (index===0) {
Navlist[2].className = 'active';//到达第一张图的时候(最后一张,)进行重新赋值上色
}
else {
Navlist[index-1].className = 'active';//根据下面序号比上面少一上色
}
}
踩坑即心得
- 关于定视器的时间问题,封装js中有一个定时器,我们自动播放也有一个定时器。首先要注意自动播放的时间要大于js中的,否则鬼畜。
当我们要实现点击可以达到切换功能的时候,定时器要及时清理掉。
还有一个无法解决的问题,当快速点击按钮的时候,由于当前动画没有实现完,你就要强人所难实现下一个,会导致鬼畜;
2.上面那个问题最终以锁定动作来解决,就是只有当当前页面滚动完才滚下一个,以后有能力再来修正。锁定的思路是
- 先定义一个ismoving=false;
- 执行每一个动作前先判断ismoving的值如果是false则执行操作;
- 操作最开始给ismoving重新赋值为true;
- 只有当回调函数执行结束之后,才会重新赋值为false来实现可以下一次操作
function next(){
//一开始isMoving的值是false,当其为false时执行下面的函数,一开始先给它进行重新的一个赋值,当函数执行结束时再给它赋值回原来的false,使其可以接着执行
if (!isMoving){
isMoving = true;
index++;
NavChange();
animate(slider,{left: -1200*index},function(){//使用回调函数来判断是否为最后一张
if (index === 4){
slider.style.left= "-1200px";//判断成立时重新进行赋值
index = 1;
}
isMoving = false;//当回调函数执行结束之后才能说明动作结束,对isMoving进行重新赋值
});
}
}
3.关于清除的问题,小点点用的是暴力清除法,不管三七二十一上来先全部清空。注意的是当我们达到第四张图的的时候,给第一个点点上色。同理当我们达到第零张图的时候给第三个点点上色。如果没有的话,我们就给当前图片序号减一的值赋给小点点上色。
4.有参考地封装了一个js函数,很好玩,以后可以再试试。这里需要注意的是回调函数,有才调用。不然报错。
贴一下完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link type="text/css"rel="stylesheet"href="shishi.css">
<script src="animation.js"></script>
</head>
<body>
<div class="box"id="box">
<div class="slider"id="slider">
<div class="slide"><img src="imgs/3.jpeg"width="1200px"height="600px"></div>
<div class="slide"><img src="imgs/1.png"width="1200px"height="600px"></div>
<div class="slide"><img src="imgs/2.jpg"width="1200px"height="600px"></div>
<div class="slide"><img src="imgs/3.jpeg"width="1200px"height="600px"></div>
<div class="slide"><img src="imgs/1.png"width="1200px"height="600px"></div>
</div>
<ul class="nav"id="nav">
<li class="active"> </li>
<li> </li>
<li> </li>
</ul>
</div>
<div id="left"><</div>
<div id="right">></div>
<script>
var box=document.getElementById('box');
var Navlist=document.getElementById('nav').children;
var slider=document.getElementById('slider');
var left=document.getElementById('left');
var right=document.getElementById('right');
var index=1;
var timer;
var isMoving = false;//这个用来锁定禁止下一步操作
function next(){
//一开始isMoving的值是false,当其为false时执行下面的函数,一开始先给它进行重新的一个赋值,当函数执行结束时再给它赋值回原来的false,使其可以接着执行
if (!isMoving){
isMoving = true;
index++;
NavChange();
animate(slider,{left: -1200*index},function(){//使用回调函数来判断是否为最后一张
if (index === 4){
slider.style.left= "-1200px";//判断成立时重新进行赋值
index = 1;
}
isMoving = false;//当回调函数执行结束之后才能说明动作结束,对isMoving进行重新赋值
});
}
}
function prve(){
if (isMoving){
return;//当isMoving为false时返回不执行下面的循环
}
isMoving = true;
index--;
NavChange();
animate(slider, {left: -1200*index}, function() {//使用回调函数来判断是否为最后一张
if (index === 0) {
slider.style.left = "-3600px";//判断成立时重新进行赋值
index = 3;
}
isMoving = false;//当回调函数执行结束之后才能说明动作结束,对isMoving进行重新赋值
});
}
var timer = setInterval(next,4000);//设定一个定时器进行轮播;这里要注意的是外层的时间要大于内层动画的时间
//鼠标滑入时使左右按键改变透明度,
box.onmouseover = function() {
animate(left, {opacity: 400});
animate(right, {opacity: 400});
clearInterval(timer);//当鼠标进入时清除定时器
}
//滑出也改变透明度,并调用函数,
box.onmouseout = function() {
animate(left, {opacity: 0});
animate(right, {opacity: 0});
timer = setInterval(next,4000);
}
//点击箭头实现功能
right.onclick = next;
left.onclick = prve;
//点击小原点到指定的地点
for (var i=0; i<Navlist.length; i++) {
Navlist[i].dex = i;
Navlist[i].onclick = function(){//这里的下标不需要锁定因为index只有几个固定的值
if (isMoving) {
return;
}
isMoving = true;
index = this.dex+1;
NavChange();
animate(slider, {left:-1200*index}, function(){isMoving=false;});
}
}
//小圆点颜色变化
function NavChange(){
for (var i=0; i<Navlist.length; i++) {//暴力清除所有点点颜色
Navlist[i].className = '';
}
if (index === 4) { //到达最后一张图(第一张的时候),重新给第一个点点上色
Navlist[0].className = 'active';
}
else if (index === 0) {
Navlist[2].className = 'active';//到达第一张图的时候(最后一张,)进行重新赋值上色
}
else {
Navlist[index-1].className = 'active';//根据下面序号比上面少一上色
}
}
</script>
</body>
</html>