React实现Header导航点击后仅当前选中链接文字变色
问题描述
近期刚开始学习编程,正在搭建个人作品集网站。开发Header导航模块时,想要实现的交互效果为:点击导航链接时,仅当前被点击的链接文字变为红色;点击其他导航链接时,之前变红的链接恢复为默认灰色,始终保持只有最新点击的链接为红色高亮状态。
目前遇到的问题:点击某链接后文字变红,但点击其他链接时,之前点击的链接仍然保持红色,无法恢复默认颜色,出现多个链接同时高亮的错误效果。
效果示例:
- 正确效果:home about work skill contact(仅about高亮)
- 错误效果:home about work skill contact(多个链接同时高亮)
技术栈为React、Tailwind CSS,配合react-scroll实现平滑滚动,原有代码如下:
Header.jsx 原有代码
import React, { useState } from "react"; import { Link as ScrollLink } from "react-scroll"; const Header = (props) => { const { headerPage } = props; const [onClickChangeColor, setOnClickChangeColor] = useState(false); const redText = () => { setOnClickChangeColor(!onClickChangeColor); }; return ( <div class="mr-8 cursor-pointer"> <ScrollLink className={onClickChangeColor ? "text-[#FF5757]" : ""} onClick={redText} to={headerPage} smooth={true} duration={500} > {headerPage} </ScrollLink> </div> ); }; export default Header;
HeaderLayout.jsx 原有代码
import React from "react"; import Header from "./Header"; const HeaderLayout = () => { const headerPages = ["home", "about", "work", "skill", "contact"]; return ( <div class="sticky top-0 flex justify-end h-20 text-md pt-10 mr-10 text-center bg-[#292929]"> {headerPages.map((headerPage) => ( <Header headerPage={headerPage}>{headerPage}</Header> ))} <div className="resume" class="w-24 h-8 text-[#FF5757] border border-[#FF5757] rounded-md" > <a href="https://drive.google.com/file/d/usp=sharing" class="block" > resume </a> </div> </div> ); }; export default HeaderLayout;
问题根源
每个导航项单独封装的Header组件都维护了独立的本地状态,点击链接时只会切换当前组件自身的高亮标记,其他导航组件的状态不会被同步重置,因此会出现多个链接同时保持红色高亮的错误效果。
修复方案
将高亮状态统一提升到父组件HeaderLayout管理,只存储当前激活的导航项标识,而非每个子组件各自维护独立的布尔值,即可保证同一时间只有一个匹配的导航项高亮。
1. 修改父组件 HeaderLayout.jsx
- 新增状态存储当前激活的导航名,默认可设为
home - 遍历渲染导航项时,把「当前激活项判断标识」和「点击修改激活项的回调」传给子组件
- 修正原代码中React混用
class/className的语法错误(React中DOM属性需要用className代替原生class)
修改后代码:
import React, { useState } from "react"; import Header from "./Header"; const HeaderLayout = () => { const headerPages = ["home", "about", "work", "skill", "contact"]; // 统一管理全局激活的导航项 const [activePage, setActivePage] = useState("home"); return ( <div className="sticky top-0 flex justify-end h-20 text-md pt-10 mr-10 text-center bg-[#292929]"> {headerPages.map((headerPage) => ( <Header key={headerPage} headerPage={headerPage} isActive={activePage === headerPage} onActiveChange={() => setActivePage(headerPage)} /> ))} <div className="resume w-24 h-8 text-[#FF5757] border border-[#FF5757] rounded-md"> <a href="https://drive.google.com/file/d/usp=sharing" className="block" > resume </a> </div> </div> ); }; export default HeaderLayout;
2. 修改子组件 Header.jsx
- 删除组件内部独立的
onClickChangeColor本地状态 - 接收父组件传入的
isActive和onActiveChange属性,直接根据isActive判断是否应用高亮样式,点击时触发父组件传入的回调更新全局激活项
修改后代码:
import React from "react"; import { Link as ScrollLink } from "react-scroll"; const Header = (props) => { const { headerPage, isActive, onActiveChange } = props; return ( <div className="mr-8 cursor-pointer text-gray-400"> <ScrollLink className={isActive ? "text-[#FF5757]" : ""} onClick={onActiveChange} to={headerPage} smooth={true} duration={500} > {headerPage} </ScrollLink> </div> ); }; export default Header;
可选优化方案
react-scroll的ScrollLink组件原生支持activeClass属性,开启滚动监听后,会自动在页面滚动到对应区块时给链接添加激活类名,无需手动维护点击状态,示例写法:
<ScrollLink activeClass="text-[#FF5757]" to={headerPage} smooth={true} duration={500} spy={true} > {headerPage} </ScrollLink>
这种写法不仅点击时会触发高亮,页面手动滚动到对应区块时也会自动同步导航高亮状态,交互体验更流畅。
内容的提问来源于stack exchange,提问作者Mayuyu
相关产品推荐
相关产品推荐

