仅在需要时,requestAnimationFrame才比总是一直使用requestAnimationFrame更快地运行动画

时间:2019-07-18 17:04:23

标签: javascript animation requestanimationframe linear-interpolation

我试图通过“消除”跟随鼠标的元素与鼠标位置之间的差异来创建“平滑”动画。

这只是出于演示目的,滚动事件和其他类型的动画也会发生此问题。

在原始代码中,requestAnimationFrame“循环”在加载JS时启动,并且永不停止。在我看来,这不是最佳的实现方法,但是动画可以通过这种方法完美地工作。

这是原始演示:https://codepen.io/ReGGae/pen/NQKENZ?editors=0010

let target = 0
let current = 0

const ease = 0.075
const element = document.querySelector('.js-lerp-me')

window.addEventListener('mousemove', (e) => {
  target = e.clientX // Stores the mouse (X) positon
})

function animate() {
  current += ((target - current) * ease) // This is where the magic happens

  element.style.transform = `translate3d(${current}px, 0, 0)`

  requestAnimationFrame(animate)
}

animate() // Runs 60 times per second

(这个例子是Jesper Landberg提供给我的,目的是向我解释忍受的事情)

在我的代码中,我尝试通过仅在触发requestAnimationFrame事件时运行mousemove“ loop”来优化它,并在事件接近完成时停止它(这几乎是因为它永远无法完成lerping) )。

我的版本:https://codepen.io/samuelgozi/pen/QeWzWy?editors=0010

let target = 0
let current = 0

const ease = 0.075
const element = document.querySelector('.js-lerp-me')

// Checks that both numbers are within a range.
// The default range is 1 because the units passed to this are pixels,
// and with lerping the last pixel never really arrives at the target.
function nearlyEqual(a, b, targetDiff = 1) {
    return Math.abs(a - b) < targetDiff;
}

window.addEventListener('mousemove', (e) => {
  target = e.clientX // Stores the mouse (X) positon
  animate()
})

function animate() {
  current += ((target - current) * ease)

  element.style.transform = `translate3d(${current}px, 0, 0)`

  if (nearlyEqual(target, current)) return // If we are close enough to the target, then dont request another animation frame.

  requestAnimationFrame(animate)
}

正如您在演示中所看到的,在我的版本中,它运行得更快,并且感觉不到“轻松”,换句话说,效果消失了。即使您降低ease乘数,它的感觉仍然有所不同。

有人可以告诉我发生了什么事吗?

1 个答案:

答案 0 :(得分:0)

原件只运行一个循环。我认为这是因为每次发生mousemove事件时,您都会启动一个新的动画,然后多个动画会同时运行,因此我修改了您的代码,只开始了一个新的动画,直到当前动画循环停止为止。

let target = 0
let current = 0
let animating = false

const ease = 0.075
const element = document.querySelector('.js-lerp-me')


// Checks that both numbers are within a range.
// The default range is 1 because the units passed to this are pixels,
// and with lerping the last pixel never really arrives at the target.
function nearlyEqual(a, b, targetDiff = 1) {
    return Math.abs(a - b) < targetDiff;
}

window.addEventListener('mousemove', (e) => {
  target = e.clientX // Stores the mouse (X) positon
  if (!animating) {
    animate()
    animating = true
  }
})

function animate() {
  current += ((target - current) * ease) // This is where the magic happens

  element.style.transform = `translate3d(${current}px, 0, 0)`

  if (nearlyEqual(target, current)) {
    animating = false
    return
  }

  requestAnimationFrame(animate)
}