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

NextJS中如何仅为鼠标悬停的组件激活对应样式属性

问题根源

你当前循环渲染的所有圆形元素共用了同一个hoverStyle状态,只要鼠标悬停触发状态更新,所有元素都会被注入同一份悬停样式,自然会出现全部加载背景图的异常效果。

实现方案

优先推荐纯CSS实现,没有额外JS状态开销,性能最好逻辑也最简洁;如果悬停效果需要联动其他JS逻辑,再用React状态控制的方案。

方案1:纯CSS实现(首选)

这类纯鼠标交互的样式完全不需要写JS监听事件,用CSS原生:hover伪类就能实现。如果你的背景图列表是动态长度,可以配合CSS变量灵活配置:

  1. 先在对应的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;
}
  1. 组件代码可以大幅简化,删掉所有和悬停相关的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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:21:10