Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/428.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
javascript动画计时:结束时速度应较慢_Javascript_Css_Animation_Requestanimationframe - Fatal编程技术网

javascript动画计时:结束时速度应较慢

javascript动画计时:结束时速度应较慢,javascript,css,animation,requestanimationframe,Javascript,Css,Animation,Requestanimationframe,我在尝试制作Javascript动画时遇到了一个问题。我希望你们能帮助我,因为我在Stackoverflow或其他网站上找不到类似的问题。警告:我喜欢写作,所以这个话题可能有点长,对此我很抱歉。我只是想把一切都说清楚。TL;DR version位于本文底部 我想做什么? 我正在构建自己的Javascript库(出于学习目的,因此我不想使用jQuery或任何其他库来解决这个问题)。这个库有很多功能,动画就是其中之一。动画是对特定元素的CSS的更改,但以平滑的方式进行。假设您有一个元素的宽度为200

我在尝试制作Javascript动画时遇到了一个问题。我希望你们能帮助我,因为我在Stackoverflow或其他网站上找不到类似的问题。警告:我喜欢写作,所以这个话题可能有点长,对此我很抱歉。我只是想把一切都说清楚。TL;DR version位于本文底部

我想做什么?
我正在构建自己的Javascript库(出于学习目的,因此我不想使用jQuery或任何其他库来解决这个问题)。这个库有很多功能,动画就是其中之一。动画是对特定元素的CSS的更改,但以平滑的方式进行。假设您有一个元素的宽度为
200px
,并且您想要使其
400px
,如果它不突然改变,而是温和地改变,它看起来会更好。我设法制作了动画,所以这不是问题所在

我的问题是什么?
动画有特定的时间范围。在此时间范围内,css从一个值更改为另一个值。时间框架,就像我做的,有下一个计算:

let timeFraction = (time - start) / this.duration;
其中
start
是调用
animate()
方法的开始时间(稍后您将看到代码)。时间是动画运行的时间,当时间和开始时间与
持续时间的数量不同时,动画即完成。
timeFraction
是自调用动画以来经过的时间量。此amount与要更改的css值相乘。我知道这听起来有点奇怪,所以让我举个例子:

我想再次将amount从
200px
更改为
400px
。这两个值之间的差值为
200px
。因此元素必须更改此值。
动画时间范围为3000毫秒。因此,动画必须在3秒内完成。1.5秒过去(3秒的一半),然后将
200px
的一半加上
200px
的现有宽度

let timeFraction = (1500 - 0) / 3000; // is 0.5
let cssAdded = timeFraction * 200; // 100px
因此,当3秒过去时,
timeFraction
应该是
1
,这将是完整的
200px

这很有魅力。动画运行平稳,但即将结束时,动画速度会慢很多。以下是一个例子:

而计算结果仍然是一样的。我只是希望它能慢慢改变,直到时间过去

我的代码是什么?
我正在使用EcmaScript 6和vanilla JS

动画制作方法:

animate(css) {
    if(this !== undefined && css) {
        this.css = css;
    }

    let start = performance.now();

    requestAnimationFrame(function animate(time) {
        let timeFraction = (time - start) / this.duration;

        if( timeFraction > 1 ) timeFraction = 1;

        let timing = this.timer(timeFraction);

        this.draw(timing);

        if ( timing < 1 ) {
            requestAnimationFrame(animate.bind(this));
        }
    }.bind(this));
}
绘制方法:

draw(timing) {
    for(let property in this.css) {

        let newValue = window.getComputedStyle(this.element)[property];
        let match = /\d+(px|em|%|rem)/.exec(newValue);

        if(match !== null) {
            newValue = match[0].replace(match[1], '');
            this.element.style[property] = Math.floor(parseInt(window.getComputedStyle(this.element)[property].replace('px', '')) - (timing * (newValue - parseInt(this.css[property].replace('px', ''))))) + match[1];
        }
        else {
            this.element.style[property] -= timing * (window.getComputedStyle(this.element)[property] - this.css[property]);
        }
    }
}
draw(timing) {
    for(let property in this.cssDiff) {
        this.element.style[property] = this.cssDiff[property].start + (timing * this.cssDiff[property].value) + this.cssDiff[property].unit;
    }
}
我尝试了什么?
首先,我尝试搜索制作javascript动画的人的例子。我尝试了他们在动画时间范围内计算css的方法,但问题没有解决。我尝试将
performance.now()
更改为
new Date().getTime()
,并从中进一步计算,但仍然出现了相同的问题。所以我不知道为什么动画的速度不总是一样的,而它应该是一样的。你们能帮忙吗

TL;DR版本
我正在用Javascript制作动画。动画是线性的(总是以相同的速度),但在动画结束时动画速度较慢(请参阅本主题中的GIF)

我的具体问题

为什么动画在最后会变慢?这有什么关系?我上面解释的计算还是别的?还是我错过了一些重要的事情?请帮忙,因为我不知道是什么原因造成的

我明白了为什么动画最后比开始慢

正如我在问题中所述,每次调用
draw
方法时都会进行计算。同样,此计算检查了要设置动画的现有css属性之间的差异,并将
定时
变量相乘(变量
timing
保存动画的时间帧。因此,当动画时间的一半过去时,
timing
等于0.5,当动画完成时,
timing
为1)

但是,由于每次调用
draw
方法时都会计算差异,因此每次的差异都是不同的。最后,当动画几乎完成时,差异非常小。虽然差异越来越小,
计时*差异也越来越小。
这将导致每次添加的差异更小(因此即使从一开始它也会变慢,但您不会注意到)

在动画开始时,我更改了代码以计算差异,现在,
计时
与该差异相乘,而不是在每个循环中再次获取差异。(此外,代码变得更清晰,更易于阅读/理解。)

动画制作方法:

animate(css) {
    if(typeof css === 'object') {
        for(let property in css) {
            this.cssDiff[property] = this.calculateDifference(property, css[property])
        }
    }
    else if(arguments.length === 2) {
        this.cssDiff[arguments[0]] = this.calculateDifference(arguments[0], arguments[1]);
    }
    else {
        return;
    }

    //The rest of the code, same as in my question...
}
绘制方法:

draw(timing) {
    for(let property in this.css) {

        let newValue = window.getComputedStyle(this.element)[property];
        let match = /\d+(px|em|%|rem)/.exec(newValue);

        if(match !== null) {
            newValue = match[0].replace(match[1], '');
            this.element.style[property] = Math.floor(parseInt(window.getComputedStyle(this.element)[property].replace('px', '')) - (timing * (newValue - parseInt(this.css[property].replace('px', ''))))) + match[1];
        }
        else {
            this.element.style[property] -= timing * (window.getComputedStyle(this.element)[property] - this.css[property]);
        }
    }
}
draw(timing) {
    for(let property in this.cssDiff) {
        this.element.style[property] = this.cssDiff[property].start + (timing * this.cssDiff[property].value) + this.cssDiff[property].unit;
    }
}
我添加了一种计算差异的方法:

calculateDifference(property, cssValue) {
    let existingCSS = window.getComputedStyle(this.element)[property];
    let match = /(\d+)(px|em|%|rem)/.exec(existingCSS);
    let differenceMap = {value: 0, unit: 0, start: 0};

    if(match !== null) {
        differenceMap.start = Number(existingCSS.replace(/px|em|%|rem/g, ''));
        differenceMap.value = Number(cssValue.replace(/px|em|%|rem/g, '')) - Number(match[1]);
        differenceMap.unit = match[2];
    }
    else {
        differenceMap.start = Number(existingCSS);
        differenceMap.value = (typeof cssValue === 'string' ? Number(cssValue.replace(/px|em|%|rem/g, '')) : cssValue) - Number(existingCSS);
    }

    return differenceMap;
}
这段代码将为每个要设置动画的css属性调用一次,因此此代码将比计算每个动画帧的差异更快

对于其他人来说,这是
计时器
方法(作为对@Blindman67问题的回答)


我希望其他想要制作JS动画的人会觉得这个问题+答案很有用。感谢大家和我一起思考,想出了一个解决方案

它看起来像是在用
(time-start)重新计算每一帧的时间/this.duration
当您调用
timer
时,随着
time
距离
start
越来越远,每次的数字都越来越大。只要动画帧及时运行,这看起来是线性的。可能您的问题在于处理CSS值的逻辑。您是否尝试在中使用时间线开发工具