如何用JavaScript/React实现动画?点击后定时修改opacity不生效问题
代码存在的核心问题
- 你使用的
setTimeout是单次执行定时器,仅会在触发后100毫秒执行1次回调逻辑,不会循环执行。所以每次调用change函数都只会运行一次o = 0 + 0.1的计算,输出自然始终为0.1。 - 变量
o的作用域被限制在change函数内部,每次调用change都会重新将o初始化为0,即便替换为循环定时器,只要o的声明位置不变,每次执行都会从0开始累加。
补充注意:0.1属于十进制不精确浮点数,连续累加可能会出现
0.30000000000000004这类精度问题,必要时可以用o = Number((o + 0.1).toFixed(1))做精度处理。
修复方案
方案1:使用setInterval实现循环执行
将状态变量提到函数外部,用循环定时器定期修改属性,适合对间隔精度要求不高的场景:
// 将状态变量和定时器标识提到全局作用域,避免每次调用change被重置 var opacity = 0; var timer = null; function change () { // 每次调用先清理之前的定时器,避免重复触发多个定时器 if(timer) clearInterval(timer); timer = setInterval(function() { opacity += 0.1; // opacity合法范围是0-1,达到最大值后停止定时器 if(opacity >= 1) { opacity = 1; clearInterval(timer); } document.querySelector("div.label").style.opacity = opacity; console.log("o = " + opacity); }, 100) }
方案2:递归调用setTimeout实现(间隔精度更高)
如果需要避免setInterval因为回调执行阻塞导致的间隔累积误差,可以用递归调用setTimeout的方式实现,状态变量通过闭包保存:
function change () { var opacity = 0; function step() { opacity += 0.1; if(opacity >= 1) { opacity = 1; document.querySelector("div.label").style.opacity = opacity; console.log("o = " + opacity); return; } document.querySelector("div.label").style.opacity = opacity; console.log("o = " + opacity); setTimeout(step, 100); } step(); }
内容的提问来源于stack exchange,提问作者Boidurja Talukdar
相关产品推荐
相关产品推荐

