基础前端

无缝连续滚动原理的实现

2019-02-07  本文已影响25人  CondorHero
无缝连续滚动示意图

原理剖析:
页面上图片复制一倍在后面,长长的火车在移动:


滚动图片
当你赋值的后半段火车的0号头贴到了盒子的左边框的时候,那么就瞬间移动到原点,重新执行动画: 动画原理图
实现步骤:

代码的实现

<!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 浏览器会把图片延迟加载,以达到最快网络体验。解决办法:

考虑到页面只有一个 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 图片的背景。

上一篇下一篇

猜你喜欢

热点阅读