如何平滑鼠标移动触发的 Framer Motion 动画?

How to smooth Framer Motion animation triggered by Mouse Move?

提问人:Unknown X 提问时间:11/8/2023 最后编辑:Unknown X 更新时间:11/8/2023 访问量:30

问:

我正在处理一个需要在鼠标拖动时调整框大小的项目,但是在尝试使用Framer Motion添加动画时遇到了一些问题。

到目前为止,我已经尝试了 2 种不同的方法。

用于处理框参数:useState

import { useState, type MouseEvent as ReactMouseEvent } from 'react'
import { motion } from 'framer-motion'

const STEP_SIZE = 40;

export default function App() {
  console.log('render')
  const [params, setParams] = useState({ top: 0, height: 0 })

  const handlerMouseDown = (e: ReactMouseEvent<HTMLDivElement>) => {
    const initialPosition = e.clientY
    const handlerMouseMove = (e: MouseEvent) => {
      const movement = e.clientY - initialPosition
      const steps = Math.ceil(Math.abs(movement) / STEP_SIZE)
      setParams({
        top: movement > 0 ? initialPosition : initialPosition - steps * STEP_SIZE,
        height: steps * STEP_SIZE
      })
    }

    const handlerMouseUp = () => {
      window.removeEventListener('mousemove', handlerMouseMove)
      window.removeEventListener('mouseup', handlerMouseUp)
    }

    window.addEventListener('mousemove', handlerMouseMove)
    window.addEventListener('mouseup', handlerMouseUp)
  }

  return (
    <div className="Container" onMouseDown={handlerMouseDown}>
      <motion.div className="Selector" animate={{ top: params.top, height: params.height }}></motion.div>
    </div>
  );
}

代码沙盒

用于避免重新渲染:useAnimation

import { type MouseEvent as ReactMouseEvent } from 'react'
import { motion, useAnimation } from 'framer-motion'

const STEP_SIZE = 40;

export default function App() {
  console.log('render')
  const controls = useAnimation()

  const handlerMouseDown = (e: ReactMouseEvent<HTMLDivElement>) => {
    const initialPosition = e.clientY
    const handlerMouseMove = (e: MouseEvent) => {
      const movement = e.clientY - initialPosition
      const steps = Math.ceil(Math.abs(movement) / STEP_SIZE)
      controls.start({ // <- change "start" to "set" for no lag but without animation
        top: movement > 0 ? initialPosition : initialPosition - steps * STEP_SIZE,
        height: steps * STEP_SIZE
      })
    }

    const handlerMouseUp = () => {
      window.removeEventListener('mousemove', handlerMouseMove)
      window.removeEventListener('mouseup', handlerMouseUp)
    }

    window.addEventListener('mousemove', handlerMouseMove)
    window.addEventListener('mouseup', handlerMouseUp)
  }

  return (
    <div className="Container" onMouseDown={handlerMouseDown}>
      <motion.div className="Selector" animate={controls}></motion.div>
    </div>
  );
}

代码沙盒

正如你所看到的,这种方法看起来很棒,但每次我移动鼠标时都会触发重新渲染。另一方面,这种方法不会重新渲染,但它看起来非常糟糕:如果我在播放时移动鼠标,动画会冻结一点。我可以用代替 ,但我希望它是动画的。useStateuseAnimationsetstart

有没有办法让它看起来流畅,同时避免重新渲染?

css reactjs css-animations framer-motion

评论


答: 暂无答案