题目:
实现一个红绿灯。
页面上存在一个div, #TrafficLight. 背景颜色默认颜色是红色,2s后变成绿色, 再2s后变成黄色,再1s后变成红色,再2s后变成绿色.... 如此一致循环。
方法一 动画的标准实现方法
实现思路:
- 使用requestAnimationFrame
- 获取到当前动画的进度。获取方式: 动画5s一次循环。当前时间和动画开始的时间得差为动画的执行的时间。与5s区余数,得到一个0-5内的数字。
- 根据进度,绘制对应颜色到按钮上
//需要展示动画的dom
var dom = document.getElementById('TrafficLight');
//动画开始时间
let startTime = new Date().getTime();
//动画总方法
function Animate(){
let now = new Date().getTime();
let animateTime = now - startTime;
let process = getProcess(animateTime);
draw(process)
window.requestAnimationFrame(Animate)
}
//动画进程
function getProcess(animateTime){
return (animateTime/1000) % 5
}
//绘制到页面上
function draw(process){
if(process < 2){
//1-2s显示红色
setBg('red')
}else if(process < 4){
//2-4s显示绿色
setBg('green')
}else {
//4-5s显示黄色
setBg('yellow')
}
}
function setBg(bgColor){
dom.style.backgroundColor = bgColor
}
//执行
Animate()
为什么使用这个方法
- 代码可扩展性强。比如今后需要改为6s一个循环,只需要改getProcess和draw方法即可。假如需要更换颜色,改draw方法即可。代码的维护成本低。
- 代码复用性强。 Animate方法基本没有任何业务代码,今后有业务代码,可以直接将Animate作为公用方法,适用任何的动画。
- 逐帧绘制,动画稳定性好,无卡顿。
- 动画可以暂停,也可以取消。
方法二 使用es6的awit
实现思路:
利用异步函数,等待ns后,绘制出相应的状态。最后,本函数内调用本函数即可实现循环效果。
//需要展示动画的dom
var dom = document.getElementById("TrafficLight");
//设置颜色
function setBg(bgColor) {
dom.style.backgroundColor = bgColor;
}
//动画入口
async function Animate() {
await sleep(2000).then(() => {
setBg("green");
});
await sleep(2000).then(() => {
setBg("yellow");
});
await sleep(1000).then(() => {
setBg("red");
});
Animate();
}
//睡眠函数
function sleep(time) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, time);
});
}
//启动动画
Animate();
分析:
- 很难实现暂停和取消。假如在vue的组件内使用,组件周期结束后,很难及时销毁动画。