React侧边栏选中项activeClassName高亮不生效如何修复
问题描述
开发带侧边栏的React应用时,整体展示效果正常,但点击侧边栏菜单项后,无法正确给已访问的页面链接标记选中高亮状态。
已经在SidebarLink组件上添加了activeClassName="selected"属性,也在对应的styled-components样式里写了.selected类的样式规则,但选中高亮始终不触发。
问题代码
import React, { useState } from "react"; import { Link } from "react-router-dom"; import styled from "styled-components"; const SidebarLink = styled(Link)` /*border: 3px solid green;*/ display: flex; color: #e1e9fc; justify-content: space-between; align-items: center; padding: 20px; list-style: none; height: 60px; text-decoration: none; font-size: 18px; &:hover { background: #252831; border-left: 4px solid #ffbc2e; cursor: pointer; } .selected { color: red; } `; const SidebarLabel = styled.span` margin-left: 16px; `; /* Used for Training dropdown */ const DropdownLink = styled(Link)` /*border: 3px solid red;*/ background: #252831; height: 60px; padding-left: 3rem; display: flex; align-items: center; text-decoration: none; color: #f5f5f5; font-size: 16px; font-weight: bold; &:hover { background: #48526F; border-left: 4px solid #ffbc2e; cursor: pointer; } `; const SubMenu = ({ item }) => { const [subnav, setSubnav] = useState(false); const showSubnav = () => setSubnav(!subnav); return ( <> <SidebarLink to={item.path} onClick={item.subNav && showSubnav} activeClassName="selected" exact> <div className="sidebarTextContainer"> <div className="sidebarIcon">{item.icon}</div> <div className="sidebarText"><SidebarLabel>{item.title}</SidebarLabel></div> </div> <div> {item.subNav && subnav ? item.iconOpened : item.subNav ? item.iconClosed : null} </div> </SidebarLink> {subnav && item.subNav.map((item, index) => { return ( <DropdownLink to={item.path} key={index}> {item.icon} <SidebarLabel>{item.title}</SidebarLabel> </DropdownLink> ); })} </> ); }; export default SubMenu;
问题原因
- styled-components里写的
.selected是后代选择器,只会匹配SidebarLink内部class为selected的子元素,但activeClassName是直接加在SidebarLink本身(最终渲染的a标签)上的,选择器写法错误导致样式不生效。 - 如果使用React Router v6及以上版本,普通
Link组件已经移除了activeClassName属性,需要用专门处理导航激活状态的NavLink组件才能实现选中效果。
修复方案
- 从
react-router-dom导入时把Link替换为NavLink,v6版本的NavLink支持通过回调函数判断当前路由是否激活,给激活状态的链接绑定自定义类名。 - 修正styled-components里的选中样式选择器,用
&.selected匹配组件自身带selected类的状态,不要写后代选择器。 - 子菜单的
DropdownLink如果需要选中高亮,同步替换为NavLink并添加对应激活样式即可。
修复后代码
import React, { useState } from "react"; // 替换Link为NavLink import { NavLink } from "react-router-dom"; import styled from "styled-components"; const SidebarLink = styled(NavLink)` /*border: 3px solid green;*/ display: flex; color: #e1e9fc; justify-content: space-between; align-items: center; padding: 20px; list-style: none; height: 60px; text-decoration: none; font-size: 18px; &:hover { background: #252831; border-left: 4px solid #ffbc2e; cursor: pointer; } /* &代表当前组件自身,匹配自身带selected类的状态 */ &.selected { color: red; background: #252831; border-left: 4px solid #ffbc2e; } `; const SidebarLabel = styled.span` margin-left: 16px; `; /* Used for Training dropdown */ const DropdownLink = styled(NavLink)` /*border: 3px solid red;*/ background: #252831; height: 60px; padding-left: 3rem; display: flex; align-items: center; text-decoration: none; color: #f5f5f5; font-size: 16px; font-weight: bold; &:hover { background: #48526F; border-left: 4px solid #ffbc2e; cursor: pointer; } /* 子菜单项选中样式 */ &.selected { color: #ffbc2e; background: #48526F; } `; const SubMenu = ({ item }) => { const [subnav, setSubnav] = useState(false); const showSubnav = () => setSubnav(!subnav); return ( <> <SidebarLink to={item.path} onClick={item.subNav && showSubnav} // v6版本通过className回调设置激活类名,v5版本可直接保留activeClassName="selected" className={({isActive}) => isActive ? "selected" : ""} end > <div className="sidebarTextContainer"> <div className="sidebarIcon">{item.icon}</div> <div className="sidebarText"><SidebarLabel>{item.title}</SidebarLabel></div> </div> <div> {item.subNav && subnav ? item.iconOpened : item.subNav ? item.iconClosed : null} </div> </SidebarLink> {subnav && item.subNav.map((item, index) => { return ( <DropdownLink to={item.path} key={index} className={({isActive}) => isActive ? "selected" : ""} > {item.icon} <SidebarLabel>{item.title}</SidebarLabel> </DropdownLink> ); })} </> ); }; export default SubMenu;
补充说明:如果还在使用React Router v5版本,不需要替换
Link为NavLink,只需要把样式里的.selected改成&.selected即可正常触发选中效果。
内容的提问来源于stack exchange,提问作者Dieter
相关产品推荐
相关产品推荐

