未捕获的TypeError:无法在“ Window”上执行“ requestAnimationFrame”:作为参数1提供的回调不是函数

问题描述

我不太确定我在这里使用requestAnimationFrame会出什么问题,因为它似乎可以正常工作,但是会引发此错误

未捕获的TypeError:无法在“窗口”上执行“ requestAnimationFrame”:作为参数1提供的回调不是函数

我试图每3000ms将一个元素旋转90度,然后淡入/淡出其他一些元素。这可能不是最优雅的方法,我怀疑不是,我对JS的理解很基础。因此,如果有人能解释造成此错误的原因,我将非常感谢。

var iteration = 0,degrees = 0;   

function rotate_by_90(degrees,iteration) {
    if(iteration <= 3) {
        var deg = degrees - 90,new_deg = deg;

        setTimeout(function() {
            $('#rotate').css('transform','translateZ(-60px) rotateX(' + deg + 'deg');
            console.log(new_deg + ' degrees');
            iteration++;
            console.log(iteration + ' iteration');
            requestAnimationFrame(rotate_by_90(new_deg,iteration));            
        },3000);
    } else {
        $('#rotating_text').fadeOut();
        $('#animation_overlay').fadeIn();
    }
};

requestAnimationFrame(rotate_by_90(degrees,iteration));

HTML

<div id="rotating_text" class="rotating_text">
    <span>Some text </span>
    <div class="rotate_container">
        <div id="rotate" class="rotate">
            <span>thing 1</span>
            <span>thing 2</span>
            <span>thing 3</span>
            <span>thing 4</span>
        </div>                              
    </div>
</div>  

<div id="animation_overlay" class="animation_overlay">                      
    <span>Some stuff</span>
</div>

此外,如果有人可以建议一种更好的方法包括在整个过程完成后循环循环以再次开始,那将非常感激!)

解决方法

不,它不起作用-您自己一次调用rotate_by_90(立即,当动画帧准备好时就没有!),并将其返回值(undefined)传递到requestAnimationFrame中。 ,您必须将 function 传递到requestAnimationFrame中,浏览器会为您调用。

您也可以传递匿名函数,因此只需添加() =>即可固定代码,

requestAnimationFrame(() => rotate_by_90(degrees,iteration));

关于总体上如何更好地执行此操作,我建议使用异步函数和实际循环:

// First,get some promisified versions of setTimeout and requestAnimationFrame:
const delay = ms => new Promise(resolve => setTimeout(resolve,ms))
const waitForAnimationFrame = () => new Promise(resolve => requestAnimationFrame(resolve))

// Next,our main function:
async function rotationAnimation () {
  let degrees = 0

  // Loop from 0 to 3
  for (let iteration = 0; iteration <= 3; iteration++) {
    // Update degrees
    degrees -= 90
    
    // Wait 3 seconds + animation frame
    await delay(3000)
    await waitForAnimationFrame()
    
    // Log variables
    console.log(`Iteration ${iteration},${degrees} degrees`)
    
    // Update the CSS
    $('#rotate').css('transform',`translateZ(-60px) rotate(${degrees}deg)`)
  }

  // After the loop is done,crossfade the elements
  $('#rotating_text').fadeOut()
  $('#animation_overlay').fadeIn()
}

// Call our main function,and handle rejections:
rotationAnimation().catch(e => console.error('Error during animation:',e))
.rotate {
  width: 60px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="rotating_text" class="rotating_text">
    <span>Some text </span>
    <div class="rotate_container">
        <div id="rotate" class="rotate">
            <span>thing 1</span>
            <span>thing 2</span>
            <span>thing 3</span>
            <span>thing 4</span>
        </div>                              
    </div>
</div>  

<div id="animation_overlay" class="animation_overlay">                      
    <span>Some stuff</span>
</div>

注意:我保留了分别计算迭代次数的原始逻辑,从0°开始,但是在第一次更新该元素之前立即减小到-90°。但是,我将rotateX更改为rotate,因为否则,示例中-90°/ -270°状态是不可见的,因为您正在查看文本的零宽度“边缘”。

(顺便说一句,您也可以只使用CSS动画来完成全部操作,而无需使用任何JavaScript。)