您好,欢迎访问一九零五行业门户网

Javascript动画的实现原理浅析_javascript技巧

假设有这样一个动画功能需求:把一个div的宽度从100px变化到200px。写出来的代码可能是这样的:
复制代码 代码如下:
function animate1(element, endvalue, duration) {
    var starttime = new date(),
        startvalue = parseint(element.style.width),
        step = 1;
var timerid = setinterval(function() {
        var nextvalue = parseint(element.style.width) + step;
        element.style.width = nextvalue + 'px';
        if (nextvalue >= endvalue) {
            clearinterval(timerid);
            // 显示动画耗时
            element.innerhtml = new date - starttime;
        }
    }, duration / (endvalue - startvalue) * step);
}animate1(document.getelementbyid('test1'), 200, 1000);
原理是每隔一定时间增加1px,一直到200px为止。然而,动画结束后显示的耗时却不止1s(一般是1.5s左右)。究其原因,是因为setinterval并不能严格保证执行间隔。有没有更好的做法呢?下面先来看一道小学数学题:
复制代码 代码如下:
a楼和b楼相距100米,一个人匀速从a楼走到b楼,走了5分钟到达目的地,问第3分钟时他距离a楼多远?
匀速运动中计算某个时刻路程的计算公式为:路程 * 当前时间 / 时间 。所以答案应为 100 * 3 / 5 = 60 。这道题带来的启发是,某个时刻的路程是可以通过特定公式计算出来的。同理,动画过程中某个时刻的值也可以通过公式计算出来,而不是累加得出:
复制代码 代码如下:
function animate2(element, endvalue, duration) {
    var starttime = new date(),
        startvalue = parseint(element.style.width);    var timerid = setinterval(function() {
        var percentage = (new date - starttime) / duration;
        var stepvalue = startvalue + (endvalue - startvalue) * percentage;
        element.style.width = stepvalue + 'px';
        if (percentage >= 1) {
            clearinterval(timerid);
            element.innerhtml = new date - starttime;
        }
    }, 13);
}
animate2(document.getelementbyid('test2'), 200, 1000);
这样改良之后,可以看到动画执行耗时最多只会有10几ms的误差。但是问题还没完全解决,在浏览器开发工具中检查test2元素可以发现,test2的最终宽度可能不止200px。仔细检查animate2函数的代码可以发现:
1.percentage的值可能大于1,可以通过math.min限制最大值解决。
2.即使保证了percentage的值不大于1,只要endvalue或startvalue为小数,(endvalue - startvalue) * percentage的值也可能产生误差,因为javascript小数运算的精度不够。其实我们要保证的只是最终值的准确性,所以在percentage为1的时候,直接使用endvalue即可。
于是,animate2函数的代码修改为:
复制代码 代码如下:
function animate2(element, endvalue, duration) {
    var starttime = new date(),
        startvalue = parseint(element.style.width);    var timerid = setinterval(function() {
        // 保证百分率不大于1
        var percentage = math.min(1, (new date - starttime) / duration);
        var stepvalue;
        if (percentage >= 1) {
            // 保证最终值的准确性
            stepvalue = endvalue;
        } else {
            stepvalue = startvalue + (endvalue - startvalue) * percentage;
        }
        element.style.width = stepvalue + 'px';
        if (percentage >= 1) {
            clearinterval(timerid);
            element.innerhtml = new date - starttime;
        }
    }, 13);
}
还有最后一个疑问:setinterval的间隔为何设为13ms?原因是当下显示器的刷新率一般不超过75hz(即每秒刷新75次,也就是每隔约13ms刷新一次),把间隔跟刷新率同步效果更好。
其它类似信息

推荐信息