React中如何根据状态动态切换SVG图标颜色?
你需要实现SidemenuItem组件根据variant的active/default状态切换传入SVG图标的颜色,以下是几种可行的实现方案:
方案一:使用currentColor(推荐)
这是最简洁且易于维护的方案,利用CSS的currentColor属性让SVG继承父元素的文字颜色,再通过组件的状态类切换颜色。
步骤1:修改传入的SVG代码
将SVG中所有固定的fill="#xxx"替换为fill="currentColor",这样SVG的颜色会自动继承父元素的color属性:
// 修改后的DashBoard SVG示例 <svg width="30" height="30" viewBox="0 0 30 30" fill="none" xmlns="http://www.w3.org/2000/svg"> <path opacity="0.5" d="M26.1039 11H16.8961..." fill="currentColor" /> <path d="M26.1039 3H16.8961..." fill="currentColor" /> <path d="M13.1035 17H3.8965..." fill="currentColor" /> <path opacity="0.5" d="M13.1035 3.00001H3.8965..." fill="currentColor" /> </svg>
步骤2:修改SidemenuItem组件
在包裹图标的span元素中,根据variant状态添加对应的颜色类:
export function SidemenuItem({ text = 'Menu Item', icon, disabled = false, children, variant = 'default', onClick }: MenuItemProps) { const handleClick: MouseEventHandler<HTMLDivElement> = (event) => { if (!disabled && onClick) { onClick(event); } }; return ( <div onClick={handleClick} className={`flex items-center ${variant !== "active" ? 'gap-3' : 'gap-5'} menu-item ${disabled ? 'cursor-not-allowed opacity-50' : ''}`} > {/* 添加颜色类:active状态用text-primary-normal,默认状态用你需要的颜色类,比如text-gray-600 */} <span className={`menu-icon flex flex-col items-end h-12 w-1/3 rounded-r-full p-3 ${variant === "active" ? 'bg-purple-20 text-primary-normal' : 'text-gray-600'}`}> {icon} </span> <p className={`menu-text ${variant === "active" ? 'text-primary-normal ml-3' : ''} font-semibold`}>{text}</p> {children} </div> ); }
方案二:通过React.cloneElement动态修改SVG属性
如果无法修改传入的SVG代码,可以使用React.cloneElement克隆图标元素,动态设置fill属性:
import { MouseEventHandler, ReactNode, cloneElement } from 'react'; export function SidemenuItem({ text = 'Menu Item', icon, disabled = false, children, variant = 'default', onClick }: MenuItemProps) { const handleClick: MouseEventHandler<HTMLDivElement> = (event) => { if (!disabled && onClick) { onClick(event); } }; // 处理图标颜色 const getColoredIcon = () => { const iconColor = variant === 'active' ? '#4C2BBF' : '#322E3D'; // 根据你的需求定义颜色 if (React.isValidElement(icon)) { // 克隆SVG元素,设置fill属性 return cloneElement(icon, { style: { ...icon.props.style, fill: iconColor }, // 如果SVG内部有path,还可以递归处理子元素,这里简化处理 }); } // 处理多个图标的情况 if (Array.isArray(icon)) { return icon.map((item, index) => React.isValidElement(item) ? cloneElement(item, { style: { ...item.props.style, fill: iconColor }, key: index }) : item ); } return icon; }; return ( <div onClick={handleClick} className={`flex items-center ${variant !== "active" ? 'gap-3' : 'gap-5'} menu-item ${disabled ? 'cursor-not-allowed opacity-50' : ''}`} > <span className={`menu-icon flex flex-col items-end h-12 w-1/3 rounded-r-full p-3 ${variant === "active" ? 'bg-purple-20' : ''}`}> {getColoredIcon()} </span> <p className={`menu-text ${variant === "active" ? 'text-primary-normal ml-3' : ''} font-semibold`}>{text}</p> {children} </div> ); }
注意:如果SVG内部有多个带独立fill的path,需要递归遍历子元素修改每个path的fill属性,这个方案相对复杂,适合无法修改SVG源文件的场景。
方案三:使用CSS滤镜(备选)
如果不想修改SVG或组件逻辑,可以用CSS的filter属性快速调整颜色,不过颜色控制不够精准:
/* 在你的CSS文件中添加 */ .menu-icon.active svg { filter: hue-rotate(180deg) brightness(1.2); /* 根据需求调整滤镜参数 */ } .menu-icon.default svg { filter: grayscale(50%); }
然后在组件中给menu-icon添加对应的类:
<span className={`menu-icon flex flex-col items-end h-12 w-1/3 rounded-r-full p-3 ${variant === "active" ? 'bg-purple-20 active' : 'default'}`}> {icon} </span>
内容的提问来源于stack exchange,提问作者hoor Iqbal
相关产品推荐
相关产品推荐

