鍍金池/ 問答/HTML5  Linux  HTML/ Javascript 中 requestAnimationFrame() 的應(yīng)用

Javascript 中 requestAnimationFrame() 的應(yīng)用問題

問題簡述:本代碼較長,建議拷貝到編輯器查看。問題是使用兩種js方法完成一個效果,個人認(rèn)為兩種方法原理一樣,但是一個效果出來了,一個沒有出效果并且報(bào)錯,想知道報(bào)錯的原因,望大神指教。

HTML代碼:

    <p>用 requestAnimationFrame 替代 seTtimeout 實(shí)現(xiàn)了一個動畫效果:</p>
    <div>
        <p class="ball red" style="margin-left:0px;"></p>
        <p class="ball green" style="margin-left:0px;"></p>
        <p class="ball blue" style="margin-left:0px;"></p>
    </div>

CSS代碼:

        .ball {
            width: 20px;
            height: 20px;
            border-radius: 50%; 
        }
        
        .red {
            background-color: red;
        }
        
        .green {
            background-color: green;
        }
        
        .blue {
            background-color: blue;
        }

JavaScript代碼方法一:

        var red = document.querySelector(".red");
        var green = document.querySelector(".green");
        var blue = document.querySelector(".blue");

        ani(red, 100, function() {
            ani(green, 200, function() {
                ani(blue, 150, function() {
                    ani(red, 150);
                    ani(green, 150)
                })
            })
        })

        //代碼一
        function ani(node, to, callback) {
            animate();

            function animate() {
                var marginLeft = parseInt(node.style.marginLeft);
                if (marginLeft == to) {
                    callback && callback();
                } else {
                    if (marginLeft < to) {
                        marginLeft++
                    } else if (marginLeft > to) {
                        marginLeft--
                    }
                    node.style.marginLeft = marginLeft + "px";
                    requestAnimationFrame(animate);
                }
            }
        }

效果沒問題:圖片描述

JavaScript代碼方法二:

        var red = document.querySelector(".red");
        var green = document.querySelector(".green");
        var blue = document.querySelector(".blue");

        ani(red, 100, function() {
            ani(green, 200, function() {
                ani(blue, 150, function() {
                    ani(red, 150);
                    ani(green, 150)
                })
            })
        })

        function ani(node, to, callback) {
            var marginLeft = parseInt(node.style.marginLeft); //本行報(bào)錯,說不識別屬性marginLeft
            if (marginLeft == to) {
                callback && callback();
            } else {
                if (marginLeft < to) {
                    marginLeft++
                } else if (marginLeft > to) {
                    marginLeft--
                }
                node.style.marginLeft = marginLeft + "px";
                requestAnimationFrame(ani);
            }
        }

效果報(bào)錯:
clipboard.png

問題:這兩種方案的差別是什么?為什么第二種方案會報(bào)錯?

回答
編輯回答
賤人曾

requestAnimationFrame(ani);表示的是瀏覽器每刷新一幀的時候就調(diào)用ani方法一次,以達(dá)到連續(xù)調(diào)用ani方法的目的(嚴(yán)格來說不“連續(xù)”,但是肉眼一般無感知)。
在下面這段代碼里你已經(jīng)調(diào)用了ani方法:

        ani(red, 100, function() {
            ani(green, 200, function() {
                ani(blue, 150, function() {
                    ani(red, 150);
                    ani(green, 150)
                })
            })
        })

你要連續(xù)調(diào)用的并不是ani,而是ani方法體里面的控制移動的部分,這就是為什么你方法一是可以成功運(yùn)行的。
方法二不可以運(yùn)行是因?yàn)?.你并不需要連續(xù)運(yùn)行ani 2.ani是有參數(shù)的 但是你沒有傳,相當(dāng)于運(yùn)行的是ani(),所以會報(bào)錯。

2017年2月23日 17:51
編輯回答
落殤
function ani(node, to, callback) {
          
            var marginLeft = parseInt(node.style.marginLeft); //本行報(bào)錯,說不識別屬性marginLeft
            
            if (marginLeft == to) {
                callback && callback();
            } else {
                if (marginLeft < to) {
                    marginLeft++
                } else if (marginLeft > to) {
                    marginLeft--
                }
           
                node.style.marginLeft = marginLeft + "px";
                requestAnimationFrame(()=>ani(node, to, callback));
            }
        }
2017年6月5日 20:37
編輯回答
蝶戀花
requestAnimationFrame(ani);

等價(jià)于:

requestAnimationFrame(function(){
    ani()
});

那么問題來了,你 ani 函數(shù)里面的各個參數(shù)必然是 undefined 啊,所以會報(bào)錯咯。

另外,你第一種方法,既然使用 requestAnimationFrame 了,本質(zhì)上是一個遞歸的邏輯,所以不用手動觸發(fā) animate 方法,直接在最后寫 requestAnimationFrame(animate) 就可以了。

最后,說點(diǎn)兒題外話,可能你有你自己的考慮,但是如果是做這種平移的特效,建議使用 transform,效果會比 margin 好。

2017年3月19日 12:26