You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

requestAnimationFrame序列执行问题:如何实现淡出后再淡入效果

问题:Canvas 淡出后淡入效果同时执行的解决方法

我想实现先淡出(fadeOut)再淡入(fadeIn)的效果,写了如下代码:

function fadeOut(content) {
    console.log('fade out');
    alpha -= delta;
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ctx.globalAlpha = alpha;
    content();
    if (alpha > 0) {
        requestAnimationFrame(fadeOut.bind(this, content));
    }
    else {
        alpha = 1;
        ctx.globalAlpha = alpha;
    }
}

function fadeIn(content) {
    console.log('fade in');
    alpha += delta;
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ctx.globalAlpha = alpha;
    content();

    if (alpha < 1) {
        requestAnimationFrame(fadeIn.bind(this, content));
    }
    else {
        alpha = 1;
        ctx.globalAlpha = alpha;
    }
}

单独调用这两个函数都正常,但如果像下面这样用requestAnimationFrame依次调用,两个效果会同时执行:

requestAnimationFrame(fadeOut.bind(this, drawMap.bind(this, MAP1)));
requestAnimationFrame(fadeIn.bind(this, drawMap.bind(this, MAP1)));

请问该怎么解决这个问题?


解决方案

你遇到的问题本质是:连续调用两次requestAnimationFrame会把两个动画函数同时加入浏览器的动画帧队列,它们会在后续的帧中并行执行,导致淡入和淡出效果重叠。

要实现严格的「先淡出再淡入」,必须在淡出动画完全结束的回调里触发淡入动画,具体修改如下:

步骤1:修改fadeOut函数,添加结束回调逻辑

在fadeOut的结束分支(alpha <= 0时),直接调用fadeIn的动画请求:

function fadeOut(content, fadeInContent) {
    console.log('fade out');
    alpha -= delta;
    // 限制alpha最小值为0,避免出现负数
    alpha = Math.max(alpha, 0);
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ctx.globalAlpha = alpha;
    content();
    
    if (alpha > 0) {
        requestAnimationFrame(fadeOut.bind(this, content, fadeInContent));
    }
    else {
        // 淡出完成,立即启动淡入动画
        requestAnimationFrame(fadeIn.bind(this, fadeInContent));
    }
}

步骤2:优化fadeIn函数的初始状态

为了避免状态残留,确保淡入从0开始:

function fadeIn(content) {
    console.log('fade in');
    // 确保alpha从0开始递增
    if (alpha <= 0) alpha = 0;
    alpha += delta;
    // 限制alpha最大值为1
    alpha = Math.min(alpha, 1);
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ctx.globalAlpha = alpha;
    content();

    if (alpha < 1) {
        requestAnimationFrame(fadeIn.bind(this, content));
    }
    else {
        alpha = 1;
        ctx.globalAlpha = alpha;
    }
}

步骤3:调用方式简化

现在只需要触发一次fadeOut,传入淡出和淡入要绘制的内容即可:

// 第一个参数:淡出时渲染的内容;第二个参数:淡入时渲染的内容
requestAnimationFrame(fadeOut.bind(this, drawMap.bind(this, MAP1), drawMap.bind(this, MAP1)));

这样就能保证两个动画严格按顺序执行,不会出现重叠的情况。


内容的提问来源于stack exchange,提问作者Dank391

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:30:32