你是对的,
requestAnimationFrame
是执行动画时避免用户界面阻塞的推荐方法。
您可以记住开始时的绝对开始时间,而不是在每一帧尝试这样做。然后,只需要根据开始时间和当前时间之间的增量时间计算宽度。
也,
document.querySelector
被认为是一个相对“沉重”的行动,所以我补充说
this.element
避免在每一帧上进行。
以下是计算新宽度的方法:
((100 - this.startWidth) / timetoEnd) * deltaT + this.startWidth
-
100 - this.startWidth
是我们必须设置动画的总宽度
-
(100 - this.startWidth) / timetoEnd
是每秒必须增加多少宽度(1)
-
((100 - this.startWidth) / timetoEnd) * deltaT
我们要加多少宽度(1)
-
我们只需要改变整个事情
this.startWidth
像素有帧的宽度
还请注意,其中一些计算是常量,不必在每一帧上计算,我将其作为练习留在这里:)
下面是您稍微修改过的代码:
let idx = 1;
const timetoEnd = 5000;
function ProgressBar(startWidth){
this.startWidth = startWidth || 0;
this.id = `pBar-${idx++}`;
this.create = () => {
let pBar = document.createElement('div');
pBar.id = this.id;
pBar.className = `p-bar`;
pBar.innerHTML = `<div class="loader"></div>`;
return pBar;
};
this.animator = () => {
const deltaT = Math.min(new Date().getTime() - this.start, timetoEnd);
if(deltaT < timetoEnd){
const width = ((100 - this.startWidth) / timetoEnd) * deltaT + this.startWidth;
this.element.style.width = `${width}%`;
requestAnimationFrame(this.animator.bind(this))
}
};
this.animate = () => {
this.element = document.querySelector(`#${(this.id)} div`);
this.start = new Date().getTime();
this.animator();
}
}
function addLoader (){
let bar1 = new ProgressBar(40);
let container = document.querySelector("#container");
container.appendChild(bar1.create());
bar1.animate();
}
.p-bar{
width: 400px;
height: 20px;
background: 1px solid #ccc;
margin: 10px;
overflow:hidden;
border-radius: 4px;
}
.p-bar .loader{
width: 0;
background: #1565C0;
height: 100%;
}
<input type="button" value="Add loader" onclick="addLoader()" />
<div id="container"></div>