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

Next.js中按空格键触发div的animate__bounceOut动画问题求助

Next.js 空格键触发CSS动画类问题排查与修复

我是一名初学者,尝试在Next.js应用中实现按下空格键时,为id为startContainer的div添加animate__bounceOut CSS动画类,但按下空格后完全没反应。我试过两种写法都没成功,具体代码和问题如下:

第一种写法(无反应)

const startContainer = window.fetch('#startContainer');

function handleKeyDown (e) {
  if (e.code ==='Space' || e.key === " ") {
    e.preventDefault();
    return true;
  }
}

useEffect(() => {
  window.addEventListener('keydown', handleKeyDown(true));
  return () => {
    startContainer.classList.add('animate__bounceOut');
    window.removeEventListener('keydown', handleKeyDown);
  }
})

return (
  <div class="rootContainer">
    <div id="startContainer" tabIndex={0} onKeyDown={handleKeyDown}></div>
    {/*svg inside*/}
  </div>
)

第二种写法(报错+无反应)

尝试用useState控制类名,但出现setSpacePressed is not a function错误,页面也没变化:

const {spacePressed, setSpacePressed} = useState(false);
useEffect(() => {
    function handleKeyDown(e) {
      if (e.code === 'Space') {
        setSpacePressed(true); {/*note: this returns an error, "setSpacePressed is not a function"*/}
      }
    }
...
return (
    <div class="rootContainer">
      <div id="startContainer" tabIndex={0} className={`$(spacePressed ? 'animate__bounceOut' : '')`}></div>
      {/*svg inside*/}
    </div>
)

问题分析

第一种写法的错误点:

  1. 获取DOM元素方式错误:window.fetch是用来发送网络请求的,获取DOM元素应该用document.getElementById或React的useRef
  2. 事件监听传参错误:handleKeyDown(true)是直接执行函数,应该传函数引用handleKeyDown,否则会立即执行函数而非绑定监听
  3. 动画类添加时机错误:清理函数(useEffect的return部分)是组件卸载时才执行,不是按下空格时触发
  4. React类名属性错误:React中元素的类名要用className,不是HTML的class
  5. 无动画触发逻辑:handleKeyDown里只做了阻止默认行为,根本没写添加动画类的代码

第二种写法的错误点:

  1. useState解构错误:useState返回的是数组,必须用数组解构const [spacePressed, setSpacePressed] = useState(false),用对象解构会导致setSpacePressed为undefined
  2. 模板字符串语法错误:应该用${}而非$(),否则无法正确解析变量
  3. 缺少animate.css基础类:animate.css动画需要元素同时拥有animate__animated基础类和目标动画类才能生效

修复方案

方案一:用useRef直接操作DOM

import { useEffect, useRef } from 'react';

export default function YourComponent() {
  // 用useRef获取DOM元素
  const startContainerRef = useRef(null);

  function handleKeyDown(e) {
    if (e.code === 'Space' || e.key === ' ') {
      e.preventDefault();
      // 确保元素存在再添加动画类
      if (startContainerRef.current) {
        startContainerRef.current.classList.add('animate__bounceOut');
      }
    }
  }

  useEffect(() => {
    // 正确绑定键盘监听
    window.addEventListener('keydown', handleKeyDown);
    // 组件卸载时移除监听,避免内存泄漏
    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    };
  }, []); // 空依赖数组确保监听只绑定一次

  return (
    <div className="rootContainer">
      <div 
        id="startContainer" 
        tabIndex={0} 
        ref={startContainerRef}
        className="animate__animated" // 必须添加animate.css基础类
      >
        {/* SVG内容 */}
      </div>
    </div>
  );
}

方案二:用useState控制类名

import { useState, useEffect } from 'react';

export default function YourComponent() {
  // 修正useState的数组解构方式
  const [spacePressed, setSpacePressed] = useState(false);

  function handleKeyDown(e) {
    if (e.code === 'Space' || e.key === ' ') {
      e.preventDefault();
      setSpacePressed(true);
    }
  }

  useEffect(() => {
    window.addEventListener('keydown', handleKeyDown);
    return () => {
      window.removeEventListener('keydown', handleKeyDown);
    };
  }, []);

  return (
    <div className="rootContainer">
      <div 
        id="startContainer" 
        tabIndex={0}
        // 修正模板字符串语法,同时添加基础类
        className={`animate__animated ${spacePressed ? 'animate__bounceOut' : ''}`}
      >
        {/* SVG内容 */}
      </div>
    </div>
  );
}

关键注意事项

  • React中优先用useRef获取DOM元素,避免直接操作document,更符合React的组件化思想
  • 确保已经正确引入animate.css库(可以通过npm安装后导入,或在HTML中添加CDN链接)
  • 如果需要动画只触发一次,可以在添加类后移除键盘监听,或者用useEffect监听spacePressed状态做后续处理

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 12:35:24