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

React中如何延迟滚轮事件监听,避免过渡动画冲突?

React滚轮路由导航动画冲突问题解决方案

我正在开发一款React应用,通过鼠标滚轮上下滚动实现路由导航,并配合对应方向的framer-motion动画:向下滚动时,下一路由从下方进入,当前路由从下方退出;向上滚动则相反。

现有实现代码

自定义Hook useAppDirection.js

import { useState, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom"

function useAppDirection(navDown, navUp, directionValueDown, directionValueUp) {
    const navigate = useNavigate();
    const location = useLocation();
    const { pathname } = location;
    const [isUp, setIsUp] = useState(false);

    useEffect(() => {
        function handleNavigation(e) {
            if (e.deltaY > 1) {
                setIsUp(false)
                setTimeout(() => {
                    navigate(navDown, { state: { value: directionValueDown } });
                }, 200)
            } else if (e.deltaY < 1) {
                setIsUp(true)
                setTimeout(() => {
                    navigate(navUp, { state: { value: directionValueUp } });
                }, 200)
            }
        }
        window.addEventListener("wheel", handleNavigation);

        return () => window.removeEventListener("wheel", handleNavigation);
    }, [pathname]);

    return { location, isUp }
}

export default useAppDirection

组件 AboutMe.js

import React from "react";
import { motion } from "framer-motion";
import useAppDirection from "../Hooks/useAppDirection";

export default function AboutMe() {
    const { isUp, location } = useAppDirection("/work", "/skills", 1000, -1000);

    return (
        <motion.div
            className="aboutme--top"
            initial={{ opacity: 0, y: location.state.value, transition: { duration: 0.8 } }}
            animate={{ opacity: 1, y: 0, transition: { duration: 0.8 } }}
            exit={{ opacity: 0, y:  isUp ? 1300 : -1300, transition: { duration: 0.8 } }}
        >
        </motion.div >
    )
}

遇到的问题

当用户向一个方向滚动触发过渡后,中途反向滚动,两个动画会同时执行,导致过渡效果卡顿、混乱。需要修改代码,确保只有当前过渡完成(约0.8秒)后,才能触发下一次滚动事件——过渡期间禁用滚轮事件监听,完成后重新启用。

解决方案

修改useAppDirection.js,添加状态控制滚轮事件的触发权限,在过渡期间禁用、完成后恢复:

import { useState, useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom"

function useAppDirection(navDown, navUp, directionValueDown, directionValueUp) {
    const navigate = useNavigate();
    const location = useLocation();
    const { pathname } = location;
    const [isUp, setIsUp] = useState(false);
    // 标记当前是否处于过渡动画中
    const [isTransitioning, setIsTransitioning] = useState(false);
    // 和组件动画时长保持一致,单位ms
    const TRANSITION_DURATION = 800;

    useEffect(() => {
        function handleNavigation(e) {
            // 过渡中直接忽略滚轮事件
            if (isTransitioning) return;

            if (e.deltaY > 1) {
                setIsUp(false);
                setIsTransitioning(true);
                setTimeout(() => {
                    navigate(navDown, { state: { value: directionValueDown } });
                    // 动画结束后重新启用滚轮
                    setTimeout(() => setIsTransitioning(false), TRANSITION_DURATION);
                }, 200);
            } else if (e.deltaY < -1) { // 修正判断逻辑,仅当明显向上滚动时触发
                setIsUp(true);
                setIsTransitioning(true);
                setTimeout(() => {
                    navigate(navUp, { state: { value: directionValueUp } });
                    setTimeout(() => setIsTransitioning(false), TRANSITION_DURATION);
                }, 200);
            }
        }
        window.addEventListener("wheel", handleNavigation);

        return () => window.removeEventListener("wheel", handleNavigation);
    }, [pathname, isTransitioning, navigate, navDown, navUp, directionValueDown, directionValueUp]);

    return { location, isUp }
}

export default useAppDirection

关键修改点

  • 新增isTransitioning状态,用于锁定过渡期间的滚轮事件
  • 在handleNavigation开头判断状态,过渡中直接返回不处理
  • 触发导航时设置isTransitioning为true,并在动画时长后重置为false,恢复滚轮监听
  • 修正向上滚动的判断逻辑:原代码e.deltaY < 1会包含无滚动的情况,改为e.deltaY < -1更精准

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:55:34