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> )
问题分析
第一种写法的错误点:
- 获取DOM元素方式错误:
window.fetch是用来发送网络请求的,获取DOM元素应该用document.getElementById或React的useRef - 事件监听传参错误:
handleKeyDown(true)是直接执行函数,应该传函数引用handleKeyDown,否则会立即执行函数而非绑定监听 - 动画类添加时机错误:清理函数(useEffect的return部分)是组件卸载时才执行,不是按下空格时触发
- React类名属性错误:React中元素的类名要用
className,不是HTML的class - 无动画触发逻辑:handleKeyDown里只做了阻止默认行为,根本没写添加动画类的代码
第二种写法的错误点:
- useState解构错误:useState返回的是数组,必须用数组解构
const [spacePressed, setSpacePressed] = useState(false),用对象解构会导致setSpacePressed为undefined - 模板字符串语法错误:应该用
${}而非$(),否则无法正确解析变量 - 缺少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
相关产品推荐
相关产品推荐

