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

如何为数组中每个Icon组件添加独立的Hover样式?

问题描述

我想把Icon组件传入其他组件,给每个Icon添加hover效果,但遇到了问题:要么hover效果不生效,要么所有Icon同时触发hover,而不是当前被hover的单个Icon。

现有代码

CollapseFilter 组件

import { Accordion } from './Accordion';
import { filterData } from '../../../../Shared/BazaData/filterData';

export const CollapseFilter = () => {
    const data = filterData.name.map((item, index) => {
        const Icon = filterData.icons[index]
        return (
            <>
                <div className='accordion'  >
                     <Accordion  icon={<Icon/>} data={item.name} />
                </div>
            </>
        )
    })
    return (
        <>
            <div>
                <div>
                    {data}
                </div>
            </div>
        </>
    )
}

Accordion 组件

import React, { useState } from 'react';
import { Down } from "../../../../Shared/icons/Down"

export const Accordion = ({ data, icon }) => {
    const [isOpen, setIsOpen] = useState(false)
    const [hover, setHover] = useState(false);
    const [mouseover, setMouseover] = useState(false)
    
    const ChangeDownIconColor = {
        transform: isOpen ? 'rotate(180deg)' : '',
        transition: 'transform 180ms ease',
        fill: isOpen ? '#663FD7' : mouseover ? '#663FD7' : ''
    }
    const ChangeIconColor = {
        fill: isOpen ? '#663FD7' : mouseover ? '#663FD7' : ''
    }
    const ChangeDataTextColor = {
        color: isOpen ? '#663FD7' : mouseover ? '#663FD7' : ''
    }
  
    return (
        <>
            <div className="accordion_container" onMouseOver={() => setMouseover(true)} onMouseLeave={() => setMouseover(false)}  onClick={() => setIsOpen(!isOpen)}>
                <button className="button_container"  >  
                    <div style={ChangeIconColor}>{icon}</div> 
                    <div className="title" style={ChangeDataTextColor} >{data}</div>
                </button>
                <Down style={ChangeDownIconColor}/>
            </div>
        </>
    )
}
解决方案

核心问题分析

  1. 你把渲染完成的<Icon/>元素作为props传入,外层div添加的fill样式无法传递到Icon内部的<svg>标签上(fill是SVG专属属性,不是普通CSS样式),导致hover样式不生效。
  2. 虽然每个Accordion组件独立维护mouseover状态,但样式作用对象错误,才会出现"要么没效果,要么全触发"的假象。

方案1:让Icon组件接收fill属性(推荐)

修改你的自定义Icon组件,让它支持接收fill属性并传递给内部SVG标签:

// 示例:自定义Icon组件的修改方式
export const ExampleIcon = ({ fill = "currentColor" }) => {
  return (
    <svg fill={fill} width="20" height="20" viewBox="0 0 24 24">
      {/* SVG路径内容 */}
    </svg>
  )
}

然后修改Accordion组件,直接给Icon传递fill属性,同时调整父组件传参方式(传递组件而非渲染完成的元素):

修改后的Accordion组件

import React, { useState } from 'react';
import { Down } from "../../../../Shared/icons/Down"

export const Accordion = ({ data, icon: Icon }) => {
    const [isOpen, setIsOpen] = useState(false)
    const [mouseover, setMouseover] = useState(false)
    
    // 统一计算当前颜色
    const activeColor = isOpen || mouseover ? '#663FD7' : 'inherit'
  
    return (
        <div className="accordion_container" 
             onMouseOver={() => setMouseover(true)} 
             onMouseLeave={() => setMouseover(false)}  
             onClick={() => setIsOpen(!isOpen)}>
            <button className="button_container">  
                <Icon fill={activeColor} /> {/* 直接给Icon传fill属性 */}
                <div className="title" style={{ color: activeColor }}>
                    {data}
                </div>
            </button>
            <Down style={{
                transform: isOpen ? 'rotate(180deg)' : '',
                transition: 'transform 180ms ease',
                fill: activeColor
            }}/>
        </div>
    )
}

修改后的CollapseFilter组件

import { Accordion } from './Accordion';
import { filterData } from '../../../../Shared/BazaData/filterData';

export const CollapseFilter = () => {
    const data = filterData.name.map((item, index) => {
        const Icon = filterData.icons[index]
        return (
            <div key={index} className='accordion'> {/* 必须添加key,避免React警告 */}
                 <Accordion icon={Icon} data={item.name} />
            </div>
        )
    })
    return (
        <div>
            {data}
        </div>
    )
}

方案2:用CSS伪类实现hover(更简洁)

如果不想修改Icon组件,直接用CSS的:hover伪类控制样式,无需维护mouseover状态:

添加CSS样式

/* hover状态样式 */
.accordion_container:hover .icon-wrapper svg,
.accordion_container:hover .title,
.accordion_container:hover .down-icon {
    fill: #663FD7;
    color: #663FD7;
}

/* 展开状态样式 */
.accordion_container.open .icon-wrapper svg,
.accordion_container.open .title,
.accordion_container.open .down-icon {
    fill: #663FD7;
    color: #663FD7;
}

.down-icon {
    transition: transform 180ms ease;
}

.accordion_container.open .down-icon {
    transform: rotate(180deg);
}

修改后的Accordion组件

import React, { useState } from 'react';
import { Down } from "../../../../Shared/icons/Down"

export const Accordion = ({ data, icon }) => {
    const [isOpen, setIsOpen] = useState(false)
  
    return (
        <div className={`accordion_container ${isOpen ? 'open' : ''}`} 
             onClick={() => setIsOpen(!isOpen)}>
            <button className="button_container">  
                <div className="icon-wrapper">{icon}</div> 
                <div className="title">{data}</div>
            </button>
            <Down className="down-icon"/>
        </div>
    )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:05:40