1. 程式人生 > >第九節 JS運動應用

第九節 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

    圖片下拉效果(運動框架)

      可改為淡入淡出

  加入自動播放

    和選項卡一樣

 

重要知識點:

  多物體運動

  任意值運動