如何在JSX中添加JavaScript实现鼠标悬停显示效果?
问题:React中实现鼠标悬停显示元素功能失败
我正在学习JavaScript和React,想实现一个鼠标悬停效果——当鼠标悬停在.tech-title元素上时,显示默认隐藏(CSS中visibility: hidden)的.tech-text元素,但代码运行有问题,请求帮助。
我的代码:
const Resume = () => { let techTitle = document.querySelectorAll('.tech-title') let techText = document.querySelectorAll('.tech-text') function cardDisplay() { techTitle.addEventListener('mouseover', () => { techText.style.visibility = 'visible' }) } return ( <div className="app-container"> <Profile /> <div className="right-container"> <Navigation /> <div className="display"> <h2 className="exp-title">A propos de moi</h2> <p className="about-me"> Curieux de nature, je suis à la recherche d'un nouvel environnement de travail pour une première expérience en tant que Développeur, je suis motivé et prêt à apprendre de nouvelles compétences. </p> <h3 className="skills">Skills</h3> <div class="skill-content"> <div className="skill-card"> <i className="fa-solid fa-puzzle-piece"></i> <h4 className="skill-title">Réflexion</h4> <p className="skill-text"> Je trouve très stimulant le fait d'analyser un problème afin d'en trouver la solution </p> </div> <div class="skill-card"> <i className="fa-solid fa-people-group"></i> <h4 className="skill-title">Travail en équipe</h4> <p className="skill-text"> Je suis à l'aise pour travailler en équipe ainsi que pour m'exprimer en public </p> </div> <div className="skill-card"> <i className="fa-solid fa-user-ninja"></i> <h4 className="skill-title">Capacité d'apatation</h4> <p className="skill-text"> Je suis capable de m'adapter à tout type de situation ainsi que de gérer mon stress </p> </div> <div className="skill-card"> <i className="fa-solid fa-lightbulb"></i> <h4 className="skill-title">Curiosité</h4> <p className="skill-text"> Curieux de nature, j'adore apprendre de nouvelles connaissances et compétences </p> </div> </div> <h3 className="skills">Tech</h3> <div className="tech-container"> <div className="tech-card"> <div className="img-tech"></div> <h4 className="tech-title">Html, CSS</h4> <p className="tech-text">bla</p> </div> <div className="tech-card"> <div className="img-tech"></div> <h4 className="tech-title">SASS</h4> <p className="tech-text"></p> </div> <div className="tech-card"> <div className="img-tech"></div> <h4 className="tech-title">Javascript</h4> <p className="tech-text">bla</p> </div> <div className="tech-card"> <div className="img-tech"></div> <h4 className="tech-title">React Js</h4> <p className="tech-text">bla</p> </div> </div> </div> </div> </div> ) } export default Resume
问题分析与修复方案
你的代码存在三个核心问题:
- DOM操作时机错误:组件初始化时调用
document.querySelectorAll,此时组件还未渲染到DOM,获取的是空集合,无法绑定事件。React不推荐直接操作DOM,应使用内置的状态和事件机制。 - NodeList操作错误:
querySelectorAll返回的是多个元素的集合,不能直接调用addEventListener或修改style,必须遍历每个元素。 - 事件绑定函数未执行:定义了
cardDisplay但从未调用,导致事件绑定根本没生效。
推荐修复方案:组件化+React状态管理
将每个技术卡片抽成独立子组件,让每个卡片自己管理悬停状态,符合React组件化思想,代码更易维护:
import React, { useState } from 'react'; // 抽离技术卡片子组件 const TechCard = ({ title, text }) => { const [isHovered, setIsHovered] = useState(false); return ( <div className="tech-card"> <div className="img-tech"></div> <h4 className="tech-title" onMouseOver={() => setIsHovered(true)} onMouseOut={() => setIsHovered(false)} > {title} </h4> <p className="tech-text" style={{ visibility: isHovered ? 'visible' : 'hidden' }} > {text} </p> </div> ); }; const Resume = () => { return ( <div className="app-container"> <Profile /> <div className="right-container"> <Navigation /> <div className="display"> <h2 className="exp-title">A propos de moi</h2> <p className="about-me"> Curieux de nature, je suis à la recherche d'un nouvel environnement de travail pour une première expérience en tant que Développeur, je suis motivé et prêt à apprendre de nouvelles compétences. </p> <h3 className="skills">Skills</h3> <div className="skill-content"> <div className="skill-card"> <i className="fa-solid fa-puzzle-piece"></i> <h4 className="skill-title">Réflexion</h4> <p className="skill-text"> Je trouve très stimulant le fait d'analyser un problème afin d'en trouver la solution </p> </div> <div className="skill-card"> <i className="fa-solid fa-people-group"></i> <h4 className="skill-title">Travail en équipe</h4> <p className="skill-text"> Je suis à l'aise pour travailler en équipe ainsi que pour m'exprimer en public </p> </div> <div className="skill-card"> <i className="fa-solid fa-user-ninja"></i> <h4 className="skill-title">Capacité d'apatation</h4> <p className="skill-text"> Je suis capable de m'adapter à tout type de situation ainsi que de gérer mon stress </p> </div> <div className="skill-card"> <i className="fa-solid fa-lightbulb"></i> <h4 className="skill-title">Curiosité</h4> <p className="skill-text"> Curieux de nature, j'adore apprendre de nouvelles connaissances et compétences </p> </div> </div> <h3 className="skills">Tech</h3> <div className="tech-container"> <TechCard title="Html, CSS" text="bla" /> <TechCard title="SASS" text="" /> <TechCard title="Javascript" text="bla" /> <TechCard title="React Js" text="bla" /> </div> </div> </div> </div> ); }; export default Resume;
替代方案:父组件统一管理悬停状态
如果不想抽离子组件,可以在父组件中用索引跟踪当前悬停的卡片:
import React, { useState } from 'react'; const Resume = () => { const [hoveredIndex, setHoveredIndex] = useState(null); // 把技术项数据抽成数组,方便遍历 const techItems = [ { title: 'Html, CSS', text: 'bla' }, { title: 'SASS', text: '' }, { title: 'Javascript', text: 'bla' }, { title: 'React Js', text: 'bla' }, ]; return ( <div className="app-container"> <Profile /> <div className="right-container"> <Navigation /> <div className="display"> {/* 其他内容保持不变 */} <h3 className="skills">Tech</h3> <div className="tech-container"> {techItems.map((item, index) => ( <div className="tech-card" key={index}> <div className="img-tech"></div> <h4 className="tech-title" onMouseOver={() => setHoveredIndex(index)} onMouseOut={() => setHoveredIndex(null)} > {item.title} </h4> <p className="tech-text" style={{ visibility: hoveredIndex === index ? 'visible' : 'hidden' }} > {item.text} </p> </div> ))} </div> </div> </div> </div> ); }; export default Resume;
不推荐方案:原生DOM操作(仅作参考)
如果一定要用原生DOM操作,需要用useEffect在组件渲染完成后绑定事件,同时添加清理函数防止内存泄漏:
import React, { useEffect } from 'react'; const Resume = () => { useEffect(() => { const techTitles = document.querySelectorAll('.tech-title'); const techTexts = document.querySelectorAll('.tech-text'); // 遍历绑定事件 techTitles.forEach((title, index) => { const text = techTexts[index]; const showText = () => text.style.visibility = 'visible'; const hideText = () => text.style.visibility = 'hidden'; title.addEventListener('mouseover', showText); title.addEventListener('mouseout', hideText); // 清理函数 return () => { title.removeEventListener('mouseover', showText); title.removeEventListener('mouseout', hideText); }; }); }, []); // 空依赖确保只执行一次 return ( {/* 原返回内容保持不变 */} ); }; export default Resume;
内容的提问来源于stack exchange,提问作者jouce
相关产品推荐
相关产品推荐

