第九节 JS运动应用

多物体运动框架

  多个物体同时运动

    例子:多个Div,鼠标移入变宽

      单定时器,存在问题

      每个Div一个定时器

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多个div变宽</title>
    <style>
        div{
            width: 100px;
            height: 50px;
            background: red;
            margin: 10px;
        }
        /*鼠标移入时宽度变宽;鼠标移除,恢复原状*/
    </style>
    <script>
        // window.onload = function () {
        //     var aDiv = document.getElementsByTagName('div');
        //     for (var i=0; i<aDiv.length; i++){
        //         aDiv[i].onmouseover = function(){
        //             startMove(this, 400)
        //         };
        //         aDiv[i].onmouseout = function(){
        //             startMove(this, 100)
        //         };
        //     }
        // };
        //
        // var timer = null;
        // function startMove(obj, iTarget){
        //     clearInterval(timer);
        //     timer = setInterval(function () {
        //         var speed = (iTarget - obj.offsetWidth)/6;
        //         speed = speed>0?Math.ceil(speed):Math.floor(speed);
        //         if (obj.offsetWidth==iTarget) {
        //             clearInterval(timer);
        //         } else {
        //             obj.style.width = obj.offsetWidth+speed+'px';
        //         }
        //     }, 30);
        // }

        //问题是,当我们把鼠标移入一个div,并快速移出,然后快速移入下一个div时,鼠标移入的第一个div有可能不能恢复原状,
        //其实问题的根源就是 整个程序就只有一个“定时器”,当第一个div在动的时候,还没有完全恢复,第二个div的定时器已经把
        // 上一个的定时器覆盖掉,所以出现这种情况,解决办法如下:
        window.onload = function () {
            var aDiv = document.getElementsByTagName('div');
            for (var i=0; i<aDiv.length; i++){
                aDiv[i].timer = null;   //自定义属性,给每个div都加一个定时器

                aDiv[i].onmouseover = function(){
                    startMove(this, 400)
                };
                aDiv[i].onmouseout = function(){
                    startMove(this, 100)
                };
            }
        };
        // var timer = null;
        function startMove(obj, iTarget){
            clearInterval(obj.timer);   //关闭相应div的定时器
            obj.timer = setInterval(function () {   //开启相应div的定时器
                var speed = (iTarget - obj.offsetWidth)/6;
                speed = speed>0?Math.ceil(speed):Math.floor(speed);
                if (obj.offsetWidth==iTarget) {
                    clearInterval(obj.timer);   //关闭相应div的定时器
                } else {
                    obj.style.width = obj.offsetWidth+speed+'px';
                }
            }, 30);
        }
    </script>
</head>
<body>
    <div></div>
    <div></div>
    <div></div>
</body>
</html>
View Code

 

多物体运动框架

  定时器作为物体的属性

  参数传递:物体、目标值

  例子:多个Div淡出淡入

    所有东西都不能共用

    属性与运动对象:速度、其他属性值(如透明度)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多个div淡入淡出</title>
    <style>
        div{
            width: 200px;
            height: 200px;
            margin: 20px;
            float: left;
            background: red;
            filter: alpha(opacity: 30);
            opacity: 0.3;
        }
    </style>
    <script>
        window.onload=function () {
            var aDiv = document.getElementsByTagName('div');

            for (var i=0; i<aDiv.length;i++){
                aDiv[i].alpha = 30;     //把每个div的alpha分开

                aDiv[i].onmouseover = function () {
                    startMove(this, 100);
                };
                aDiv[i].onmouseout = function (){
                    startMove(this, 30);
                };
            }
        };
        // var alpha = 30;     //虽然把alpha分开了不同的div,但是任然存在鼠标快速由一个div移入到另一个div时,透明度变化较慢的情况
        // 所以我们的解决办法是,把每个div的alpha也分开,
        function startMove(obj, iTarget) {
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                var speed = (iTarget-obj.alpha)/6;
                speed = speed>0?Math.ceil(speed):Math.floor(speed);
                
                if (obj.alpha==iTarget) {
                    clearInterval(obj.timer);
                } else {
                    obj.alpha+=speed;
                    obj.style.filter = 'alpha(opacity: '+obj.alpha+')';
                    obj.style.opacity = obj.alpha/100;
                }
            }, 30);
        }
    </script>
</head>
<body>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</body>
</html>
View Code

 

任意值的运动框架

  offset属性的Bug

    有边框的Div变宽

      用currentSty代替offset

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>a_bug_of_offset</title>
    <style>
        #div1{
            width: 200px;
            height: 200px;
            background: red;
            border: 1px solid black;
        }
        #div2{
            height: 200px;
            background: red;
            border: 1px solid black;
        }
        #div3{
            width: 200px;
            height: 200px;
            background: red;
            border: 1px solid black;
        }
    </style>
    <script>
        setInterval(function () {
            var oDiv1 = document.getElementById('div1');

            oDiv1.style.width = oDiv1.offsetWidth-1+'px';
            //问题来了,样式表中未加“border”之前,div确实在一直变窄,直至消失,而加入“border”之后div就开始慢慢变宽了,
            //原因是,offsetwidth获得的是div的“盒模型”(其中包括:border、padding、width等等)尺寸,究其根本原因是
            //因为width=200 左右border为2 offsetWidth=200+2=202,202-1=201px赋值给Width;
            //现在offsetWidth=201+2=203px 203-1=202px再赋值给Width;
            //offsetWidth=202+2=204px 204-1=203px再赋值给Width;如此继续,Width会越来越大,div的宽度也就越来越宽
            //
            //另外,同理,当改为:“oDiv.style.width = oDiv.offsetWidth-2+'px';”时,原先offsetWidth=200+2=202px,
            //offsetWidth-2=200px赋值给width,offsetWidth有等于200+2px,如此反复,width始终等于200px,
            //offsetWidth始终等于202px,所以当“-2”时,div不发生任何变化,
        }, 30);

        //解决办法是不使用offsetWidth 如下,把div2的width放到行间
        setInterval(function () {
            var oDiv2 = document.getElementById('div2');
            oDiv2.style.width = parseInt(oDiv2.style.width)-1+'px';
        }, 30);

        //上述解决办法,又存在一个局限性,因为“a.style.b”只能获取行间样式,而不能获取样式表中的样式,解决办法是:
        function getStyle(obj, name){   //该方法帮助我们获取非行间(样式表里的)样式
            if(obj.currentStyle){
                return obj.currentStyle[name];
            } else {
                return getComputedStyle(obj, false)[name];
            }
        }
        setInterval(function () {
            var oDiv3 = document.getElementById('div3');
            oDiv3.style.width = parseInt(getStyle(oDiv3, 'width'))-1+'px';
        }, 30);
    </script>
</head>
<body>
    <div id="div1"></div>
    <div id="div2" style="width: 200px"></div>
    <div id="div3"></div>
</body>
</html>
View Code

     

  原有运动框架的问题:只能让某个值运动起来,如果想让其他值运动起来,要修改程序

    由上述代码我们可以看出,offset...存在相应的bug,所以之前用过offset...的相关代码也会有同样的错误出现,开始用“offset...”仅仅是因为它比较简单,而且很容易让人们理解运动的概念,但是之后为了避免此类错误的出现,我们就不再优先考虑offset...了,所以下面改进版的“任意值的运动框架-改进版”如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>任意值变化框架-改进版</title>
    <style>
        div{
            width: 200px;
            height: 200px;
            margin: 20px;
            float: left;
            background: red;
            font-size: 14px;
            border: 1px solid blue;
        }
    </style>
    <script>
        window.onload = function () {
            var oDiv1 = document.getElementById('div1');
            oDiv1.onmouseover = function () {
                startMove(this, 'height', 400);
            };
            oDiv1.onmouseout = function (){
                startMove(this, 'height', 200);
            };

            var oDiv2 = document.getElementById('div2');
            oDiv2.onmouseover = function () {
                startMove(this, 'width', 400);
            };
            oDiv2.onmouseout = function (){
                startMove(this, 'width', 200);
            };

            var oDiv3 = document.getElementById('div3');
            oDiv3.onmouseover = function () {
                startMove(this, 'font-size', 24);   //font-size也可以写成fontSize
            };
            oDiv3.onmouseout = function () {
                startMove(this, 'fontSize', 14);   //font-size也可以写成fontSize
            }

            var oDiv4 = document.getElementById('div4');
            oDiv4.onmouseover = function () {
                startMove(this, 'border-width', 24);    //border-width也可以写成borderWidth
            };
            oDiv4.onmouseout = function () {
                startMove(this, 'border-width', 1);     //border-width也可以写成borderWidth
            }
        };

        function getStyle(obj, name){   //该方法帮助我们获取非行间(样式表里的)样式
            if(obj.currentStyle){
                return obj.currentStyle[name];
            } else {
                return getComputedStyle(obj, false)[name];
            }
        }

        function startMove(obj, attr, iTarget) {
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                var cur = parseInt(getStyle(obj, attr));

                var speed = (iTarget-cur)/6;
                speed = speed>0?Math.ceil(speed):Math.floor(speed);

                if (cur==iTarget) {
                    clearInterval(obj.timer);
                } else {
                    obj.style[attr] = cur+speed+'px';
                }
            }, 30);
        }
    </script>
</head>
<body>
    <div id="div1">变长</div>
    <div id="div2">变宽</div>
    <div id="div3">字体变大</div>
    <div id="div4">变宽</div>
</body>
</html>
View Code

 

扩展的运动框架:

  运动属性作为参数

  封装opacity

    小数的问题   

  但是由于我们在上述代码中用的是:parseInt()进行取整,但是如果我们在使用透明度的时候都需要用到小数,所以此时由于parseInt()的使用,又限制了程序的完整性,解决办法如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>parseInt局限的改进</title>
    <style>
        div{
            width: 200px;
            height: 200px;
            margin: 20px;
            float: left;
            background: red;
            font-size: 14px;
            border: 10px solid blue;
            filter: alpha(opacity: 30); /*IE浏览器 物体透明度*/
            opacity: 30%;    /*Chrome、FF浏览器 物体透明度,也可以写成0.3*/
        }
    </style>
    <script>
        window.onload = function () {
            var oDiv1 = document.getElementById('div1');
            oDiv1.onmouseover = function () {
                startMove(this, 'opacity', 100);
            };
            oDiv1.onmouseout = function (){
                startMove(this, 'opacity', 30);
            };
        };

        function getStyle(obj, name){   //该方法帮助我们获取非行间(样式表里的)样式
            if(obj.currentStyle){
                return obj.currentStyle[name];
            } else {
                return getComputedStyle(obj, false)[name];
            }
        }

        function startMove(obj, attr, iTarget) {
            clearInterval(obj.timer);
            obj.timer = setInterval(function () {
                var cur = 0;

                if (attr == 'opacity') {
                    cur = Math.round(parseFloat(getStyle(obj, attr))*100);  //乘以100符合咱们平时对opacity的设置 Math.round()下面会有介绍
                } else {
                    cur = parseInt(getStyle(obj, attr));
                }

                var speed = (iTarget-cur)/6;
                speed = speed>0?Math.ceil(speed):Math.floor(speed);

                if (cur==iTarget) {
                    clearInterval(obj.timer);
                } else {
                    if (attr == 'opacity') {
                        obj.style.filter = 'alpha(opacity:'+(cur+speed)+')';    //IE透明度
                        obj.style.opacity = (cur+speed)/100;

                        var oTxt = document.getElementById('txt1');
                        oTxt.value = obj.style.opacity;
                    } else {
                        obj.style[attr] = cur+speed+'px';
                    }

                }
            }, 30);
        }


        // alert(0.06*100);    //返回值为 6 没错
        // alert(0.07*100);    //返回值为:7.000000000000001,出现误差,
        // // 这是由于计算机存储容量有限,所以计算机并不一定会全部存储数据的实际值,而是近似值,但是只要是近似值就会有误差,
        // // 但是这并不会妨碍我们的使用,而且并不是PC存在这个问题,手机等计算设备都会有这种问题。
        // // 目前这种情况已经相对很少出现了,当然我们也有解决办法 Math.round() 四舍五入
        // alert(Math.round(3.499999999999999));   //返回值为3
        // alert(Math.round(3.4999999999999999));   //返回值为4
    </script>
</head>
<body>
    <div id="div1">变长</div>
    <input id="txt1" type="text"/>
</body>
</html>
View Code

 

仿Flash图片展示 - 1

  效果思路:

    两边的按钮——淡入淡出

    大图下拉——层级、高度变化

    下方的li——多物体淡入淡出

    下方的ul——位置计算

  左右按钮

    淡出淡入

      鼠标移动到按钮上,按钮会消失

        层级问题

        按钮和遮罩上都得加上事件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>仿Flash图片轮转效果</title>
    <link rel="stylesheet" type="text/css" href="31.css"/>
    <script src="31JS_StartMove.js"></script>
    <script>
        function getByClass(oParent, sClass){
            var aEle = oParent.getElementsByTagName("*");
            var aResult = [];   //存储选出来的结果

            for(var i=0; i<aEle.length; i++){
                if (aEle[i].className == sClass){
                    aResult.push(aEle[i]);
                }
            }
            return aResult;
        }

        window.onload = function(){
            var oDiv = document.getElementById('playimages');
            var oBtnPrev = getByClass(oDiv, 'prev')[0];
            var oBtnNext = getByClass(oDiv, 'next')[0];
            var oMarkLeft = getByClass(oDiv, 'mark_left')[0];
            var oMarkRight = getByClass(oDiv, 'mark_right')[0];

            var oDivSmall = getByClass(oDiv, 'small_pic')[0];
            var oUlSmall = oDivSmall.getElementsByTagName('ul')[0];
            var aLiSmall = oDivSmall.getElementsByTagName('li');

            var oUlBig = getByClass(oDiv, 'big_pic')[0];
            var aLiBig = oUlBig.getElementsByTagName('li');

            var nowZIndex = 2;    //用于改变图片的层级,层级越大,图片越靠上,最大层级的图片永远在最上方
            var now = 0;    //为上一张和下一张做准备

            oUlSmall.style.width = aLiSmall.length*aLiSmall[0].offsetWidth+'px';    //把放小图的div加宽,使其能放下所有图片

            //左右按钮
            oBtnPrev.onmouseover = oMarkLeft.onmouseover = function () {
                startMove(oBtnPrev, 'opacity', 100);
            };
            oBtnPrev.onmouseout = oMarkLeft.onmouseout = function () {
                startMove(oBtnPrev, 'opacity', 0);
            };

            oBtnNext.onmouseover = oMarkRight.onmouseover = function () {
                startMove(oBtnNext, 'opacity', 100);
            };
            oBtnNext.onmouseout = oMarkRight.onmouseout = function () {
                startMove(oBtnNext, 'opacity', 0);
            };

            //大图切换
            for (var i=0; i<aLiSmall.length; i++){
                aLiSmall[i].index = i;
                aLiSmall[i].onclick = function(){
                    //计算当前是哪一张照片,如果是当前显示的图片,点击小图切换是,如果点击的小图和显示的大图对应,则大图没有反应即可,避免图片重复刷新
                    if (this.index == now) return;

                    now = this.index;

                    tab();  //函数调用
                };

                aLiSmall[i].onmouseover = function () {
                    startMove(this, 'opacity', 100);
                };
                aLiSmall[i].onmouseout = function () {
                    if (this.index != now) {
                        startMove(this, 'opacity', 60);
                    }
                }
            }

            //函数封装
            function tab(){
                aLiBig[now].style.zIndex = nowZIndex++;

                for (var i=0; i<aLiSmall.length;i++){
                    startMove(aLiSmall[i], 'opacity', 60);
                }
                startMove(aLiSmall[now], 'opacity', 100);

                aLiBig[now].style.height = 0;
                startMove(aLiBig[now], 'height', 320);   //控制大图片转换,转换方式是调整图片高度

                if (now == 0){      //当图片是第一张图片时,第一张小图left=0,即靠左放
                    startMove(oUlSmall, 'left', 0);
                } else if (now == aLiSmall.length-1){   //当图片为最后一张图片时,最后一张小图靠右摆放
                    startMove(oUlSmall, 'left', -(now-2)*aLiSmall[0].offsetWidth);
                } else {    //当图片既不是第一张,也不是最后一张时,靠中间摆放
                    startMove(oUlSmall, 'left', -(now-1)*aLiSmall[0].offsetWidth);
                }
                // startMove(oUlSmall, 'left', -(now-1)*aLiSmall[0].offsetWidth)
            }

            oBtnPrev.onclick = function () {
                now--;
                if (now == -1){
                    now = aLiSmall.length-1;
                }
                tab();
            };

            oBtnNext.onclick = function () {
                now++;
                if (now == aLiSmall.length) {
                    now=0;
                }
                tab();  //函数调用
            };

            //自动播放
            var timer = setInterval(oBtnNext.onclick, 2000);
            
            oDiv.onmouseover = function () {
                clearInterval(timer);
            };
            oDiv.onmouseout = function () {
                timer = setInterval(oBtnNext.onclick, 2000);
            };
        };
    </script>
</head>
<body>
    <div id="playimages" class="play">
        <ul class="big_pic">
            <div class="prev"></div>
            <div class="next"></div>

            <div class="text">加载图片说明……</div>
            <div class="length">计算图片数量……</div>

            <a class="mark_left" href="javascript:;"></a>
            <a class="mark_right" href="javascript:;"></a>
            <div class="bg"></div>

            <li style="z-index: 1;"><img src="img/bg1.jpg"/></li>
            <li><img src="img/bg2.jpg"></li>
            <li><img src="img/bg3.jpg"></li>
            <li><img src="img/bg4.jpg"></li>
            <li><img src="img/bg5.jpg"></li>
            <li><img src="img/bg3.jpg"></li>
        </ul>
        <div class="small_pic">
            <ul style="width: 390px;">
                <li style="filter: alpha(opacity: 100); opacity: 1;"><img src="img/bg1.jpg"/></li>
                <li><img src="img/bg2.jpg"></li>
                <li><img src="img/bg3.jpg"></li>
                <li><img src="img/bg4.jpg"></li>
                <li><img src="img/bg5.jpg"></li>
                <li><img src="img/bg3.jpg"></li>
            </ul>
        </div>
    </div>
</body>
</html>
View Code
body{background: #666;}
ul{padding: 0;  margin: 0;}
li{list-style: none;}
img{border: 0;}

.play{
    width: 400px;
    height: 430px;
    margin: 50px auto 0;
    background: #999;
    font: 12px Arial;
}

.big_pic{
    width: 400px;
    height: 320px;
    overflow: hidden;
    border-bottom: 1px solid #ccc;
    background: #222;
    position: relative;
}
.big_pic li{
    width: 400px;
    height: 320px;
    overflow: hidden;
    top: 0;
    left: 0;
    z-index: 0;
    background: url("img/loading.jpg") no-repeat center center;
    position: absolute;
}
.big_pic li img{
    width: 400px;
    height: 320px;
}

.mark_left{
    width: 200px;
    height: 320px;
    position: absolute;
    left: 0;
    top: 0;
    background: red;
    filter: alpha(opacity:0);
    opacity: 0;     /*控制左右位置,使鼠标停到左边时,左键出现*/
    z-index: 3000;
}
.mark_right{
    width: 200px;
    height: 320px;
    position: absolute;
    left: 200px;
    top: 0;
    background: green;
    filter: alpha(opacity:0);
    opacity: 0;
    z-index: 3000;
}

.big_pic .prev{
    width: 60px;
    height: 60px;
    background: url("img/btn.jpg") no-repeat;
    position: absolute;
    top: 130px;
    left: 10px;
    z-index: 3001;
    /*display: none;*/
    filter: alpha(opacity:0);
    opacity: 0;
    cursor: pointer;
}
.prev .next img{
    width: 60px;
    height: 60px;
}
.big_pic .next{
    width: 60px;
    height: 60px;
    background: url("img/btn.jpg") no-repeat 0 -60px;
    position: absolute;
    top: 130px;
    right: 10px;
    z-index: 3001;
    /*display: none;*/
    filter: alpha(opacity:0);
    opacity: 0;
    cursor: pointer;
}

.big_pic .text{
    position: absolute;
    left: 10px;
    top: 302px;
    z-index: 3000;
    color: #ccc;
}
.big_pic .length{
    position: absolute;
    right: 10px;
    bottom: 4px;
    z-index: 3000;
    color: #ccc;
}
.big_pic .bg{
    width: 400px;
    height: 25px;
    background: #000;
    filter: alpha(opacity=60);
    opacity: 0.6;
    position: absolute;
    z-index: 2999;
    bottom: 0;
    left: 0;
}

.small_pic{
    width: 380px;
    height: 94px;
    position: relative;
    top: 7px;
    left: 10px;
    overflow: hidden;
}
.small_pic ul{
    height: 94px;
    position: absolute;
    top: 0px;
    left: 0px;
}
.small_pic li{
    width: 120px;
    height: 94px;
    float: left;
    padding-right: 10px;
    background: url("img/loading.jpg") no-repeat center center;
    cursor: pointer;
    filter: alpha(opacity=100);
    opacity: 0.6;
}
.small_pic li img{
    width: 120px;
    height: 94px;

}
31.css
function getStyle(obj, name){   //该方法帮助我们获取非行间(样式表里的)样式
    if(obj.currentStyle){
        return obj.currentStyle[name];
    } else {
        return getComputedStyle(obj, false)[name];
    }
}

function startMove(obj, attr, iTarget) {
    clearInterval(obj.timer);
    obj.timer = setInterval(function () {
        var cur = 0;

        if (attr == 'opacity') {
            cur = Math.round(parseFloat(getStyle(obj, attr))*100);  //乘以100符合咱们平时对opacity的设置
        } else {
            cur = parseInt(getStyle(obj, attr));
        }

        var speed = (iTarget-cur)/6;
        speed = speed>0?Math.ceil(speed):Math.floor(speed);

        if (cur==iTarget) {
            clearInterval(obj.timer);
        } else {
            if (attr == 'opacity') {
                obj.style.filter = 'alpha(opacity:'+(cur+speed)+')';    //IE透明度
                obj.style.opacity = (cur+speed)/100;

                var oTxt = document.getElementById('txt1');
                oTxt.value = obj.style.opacity;
            } else {
                obj.style[attr] = cur+speed+'px';
            }

        }
    }, 30);
}
31JS_StartMove.js

图片自行找,然后把名字改成文件中的图片名称即可,甚至不用管你找的图片尺寸,因为在CSS样式表中有对图片调整的代码。

 

仿Flash图片展示 - 2

  下方li效果

    点击切换大图——选项卡

    li淡入淡出——移入移除

    ul移动——位置计算

  大图片切换

    图片层级——zIndex一直加1

    图片下拉效果(运动框架)

      可改为淡入淡出

  加入自动播放

    和选项卡一样

 

重要知识点:

  多物体运动

  任意值运动

 

posted @ 2019-01-13 23:10  漠上  阅读(170)  评论(0编辑  收藏  举报