NextJS中如何仅为鼠标悬停的组件激活对应样式属性
问题根源
你当前循环渲染的所有圆形元素共用了同一个hoverStyle状态,只要鼠标悬停触发状态更新,所有元素都会被注入同一份悬停样式,自然会出现全部加载背景图的异常效果。
实现方案
优先推荐纯CSS实现,没有额外JS状态开销,性能最好逻辑也最简洁;如果悬停效果需要联动其他JS逻辑,再用React状态控制的方案。
方案1:纯CSS实现(首选)
这类纯鼠标交互的样式完全不需要写JS监听事件,用CSS原生:hover伪类就能实现。如果你的背景图列表是动态长度,可以配合CSS变量灵活配置:
- 先在对应的CSS Module文件中添加样式:
.circle { /* 保留你原本的circle基础样式 */ transition: all 0.3s ease-in-out; } .circle:hover { border: 1px solid #f5f5f5; box-shadow: 0px 0px 10px #f5f5f5; background: center var(--circle-hover-bg) no-repeat; }
- 组件代码可以大幅简化,删掉所有和悬停相关的state、useEffect、鼠标监听逻辑,渲染时只需要给每个圆形元素通过行内样式传入对应背景图的CSS变量即可:
const StatsIndicadores = () => { const somearray = ['10%', '50%', '60%', '60%'] return ( <Grid container className={style.test}> {somearray.map((item, index) => ( <Grid item xs={12} md={3} key={index}> <div className={style.statsContainer}> <div className={style.circle} style={{ '--circle-hover-bg': `url("/images/stats/rounded-images/${index + 1}.png")` }} > <p className={style.circleStats}>Some value</p> <p className={`${style.circleStats} ${style.circleStatsDescription}`}>Ver más</p> </div> <p className={style.indicador}>Some name</p> </div> </Grid> ))} </Grid> ) }
方案2:React状态控制(适配悬停联动JS逻辑的场景)
如果悬停后还需要触发其他JS操作(比如埋点上报、联动其他组件渲染),不需要拆分多个state、也不需要用useEffect生成样式,只需要存当前悬停项的索引即可,渲染时逐项判断索引是否匹配,匹配的项才加载悬停样式:
const StatsIndicadores = () => { const somearray = ['10%', '50%', '60%', '60%'] // 初始值为null,代表当前没有悬停的项 const [hoverIndex, setHoverIndex] = useState(null) return ( <Grid container className={style.test}> {somearray.map((item, index) => { // 仅当前项索引和悬停索引一致时,才注入悬停样式 const circleStyle = hoverIndex === index ? { background: `center url("/images/stats/rounded-images/${index + 1}.png") no-repeat`, border: '1px solid #f5f5f5', boxShadow: '0px 0px 10px #f5f5f5', transition: 'all 0.3s ease-in-out' } : {} return ( <Grid item xs={12} md={3} key={index}> <div className={style.statsContainer}> <div className={style.circle} style={circleStyle} onMouseEnter={() => setHoverIndex(index)} onMouseLeave={() => setHoverIndex(null)} > <p className={style.circleStats}>Some value</p> <p className={`${style.circleStats} ${style.circleStatsDescription}`}>Ver más</p> </div> <p className={style.indicador}>Some name</p> </div> </Grid> ) })} </Grid> ) }
你原本的代码把悬停状态、样式对象、索引拆成三个独立state,还额外加了useEffect监听状态变化生成样式,会产生不必要的重渲染,这部分逻辑可以完全删除。
内容的提问来源于stack exchange,提问作者Miguel V
相关产品推荐
相关产品推荐

