无缝连续滚动原理的实现
2019-02-07 本文已影响25人
CondorHero
无缝连续滚动示意图
滚动图片
当你赋值的后半段火车的0号头贴到了盒子的左边框的时候,那么就瞬间移动到原点,重新执行动画: 动画原理图
实现步骤:
原理剖析:
页面上图片复制一倍在后面,长长的火车在移动:
滚动图片
当你赋值的后半段火车的0号头贴到了盒子的左边框的时候,那么就瞬间移动到原点,重新执行动画: 动画原理图
实现步骤:
- HTML CSS知识构建静态页面
- 逻辑实现使用绝对定位
- JS定时器轮播
代码的实现
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>无缝连续滚动的实现</title>
<style>
*{
margin: 0;
padding: 0;
}
.rolling{
width: 800px;
height: 130px;
border: 10px solid #ccc;
margin: 100px auto;
position: relative;
overflow: hidden;
}
.rolling .m_unit{
width: 5000px; /*这是运动的单位,这个宽度随便取,大一点,最少的大于rolling小于运动盒子的内容*/
position: absolute;
top: 0;
left: 0;
}
.rolling ul{
list-style: none;
}
.rolling ul li{
float: left;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="rolling" id="rolling">
<div class="m_unit" id="m_unit">
<ul>
<li><a href=""><img src="images/shuzi/0.png" alt="" /></a></li>
<li><a href=""><img src="images/shuzi/1.png" alt="" /></a></li>
<li><a href=""><img src="images/shuzi/2.png" alt="" /></a></li>
<li><a href=""><img src="images/shuzi/3.png" alt="" /></a></li>
<li><a href=""><img src="images/shuzi/4.png" alt="" /></a></li>
<li><a href=""><img src="images/shuzi/5.png" alt="" /></a></li>
<li><a href=""><img src="images/shuzi/6.png" alt="" /></a></li>
<li><a href=""><img src="images/shuzi/7.png" alt="" /></a></li>
</ul>
</div>
</div>
<script>
//得到元素
var rolling = document.getElementById("rolling");
var m_unit = document.getElementById("m_unit");
var listul = m_unit.getElementsByTagName("ul")[0];
//得到图片的数量,计算折返点用的,折返点就是210 * 图片数量
var lislength = listul.getElementsByTagName("li").length;
//复制一倍的li 最笨的办法直接把 li 在写一遍
listul.innerHTML += listul.innerHTML;
//信号量
var nowleft = 0;
var timer;
//默认调用move
move();
//鼠标进入
rolling.onmouseover = function(){
clearInterval(timer);
}
//鼠标离开
rolling.onmouseout = function(){
move();
}
function move(){
//运动
timer = setInterval(function(){
nowleft -= 3;
if(nowleft < -210 * lislength){
nowleft = 0;
}
m_unit.style.left = nowleft + "px";
},10);
}
</script>
</body>
</html>
滚动的回拉位置的设置方式:
- 直接计算写常量,太死板。
- 等宽,计算个数。可适应 图片个数不同。案例即是这种。
思考:
如果图片不等宽,长短不一怎么办?
解决方法有两个:
方法1:遍历前半部分(复制一倍之前)所有的li,把所有的li的宽度累加,累加之后就是折返点。offsetWidth,这个东西不带margin。所以累加的时候,有需要得到计算后的margin十分麻烦。所以我们不考虑方法1。
方法2:我们发现,折返点就是复制的假火车第1张图的offsetLeft值。所以,如果原来的li的个数是lilength,那么假火车的第1张图就是lis[length]。
先讲教训:
但是写完发现效果不对,未能达到如期预料。原因 Google 浏览器会把图片延迟加载,以达到最快网络体验。解决办法:
- 添加 window,onload()设置页面加载完,再加载 js 效果。
- 添加 img.onload() 事件。
考虑到页面只有一个 onload,这里选择第二个办法。
主要程序修改如下:
for(var i = 0 , count = 0 ; i < imgs.length ; i++){
imgs[i].onload = function(){
count++;
if(count == imgs.length){
//所有图片加载完毕了,就有折返点了:
zhefandian = lis[lislength / 2].offsetLeft;
//所有图片加载完毕了,再开始运动
move();
}
}
}
//得到元素
var rolling = document.getElementById("rolling"); //大盒子
var m_unit = document.getElementById("m_unit"); //运动单位
var listul = m_unit.getElementsByTagName("ul")[0]; //ul
var imgs = listul.getElementsByTagName("img"); //img
//图片的原来数量
var zhefandian; //折返点
//复制一倍的li
listul.innerHTML += listul.innerHTML;
//得到所有li,包括新li
var lis = listul.getElementsByTagName("li");
//所有li的个数,包括新li
var lislength = lis.length;
//现在我们要计算折返点,但是每个li的宽度都不一样,所以现在假火车的开头元素的offsetLeft就是折返点。这个元素是lis[lislength / 2];比较麻烦的是,由于Chrome的机理,如果要读取offsetLeft值必须保证所有图片加载完毕。
for(var i = 0 , count = 0 ; i < imgs.length ; i++){
imgs[i].onload = function(){
count++;
if(count == imgs.length){
//所有图片加载完毕了,就有折返点了:
zhefandian = lis[lislength / 2].offsetLeft;
//所有图片加载完毕了,再开始运动
move();
}
}
}
//信号量
var nowleft = 0;
var timer;
//鼠标进入
rolling.onmouseover = function(){
clearInterval(timer);
}
//鼠标离开
rolling.onmouseout = function(){
move();
}
function move(){
clearInterval(timer);
//运动
timer = setInterval(function(){
nowleft -= 5;
if(nowleft < -zhefandian){
nowleft = 0;
}
m_unit.style.left = nowleft + "px";
},20);
}
</script>
小tip:因页面加载图片有延迟,可以给页面添加一个加载背景,一个 GIF 图片的背景。