如何在React中实现滚动时的头部导航栏动画效果?
解决React中滚动触发导航栏样式变化的问题
问题说明
我正在复刻一个Codepen模板到React中,需要把这段jQuery实现的滚动效果转成React代码:
$(window).scroll(function () { if ($(document).scrollTop() > 50) { $(".nav").addClass("affix"); console.log("OK"); } else { $(".nav").removeClass("affix"); } });
以下是我目前的React代码,不确定如何实现滚动到一定距离时触发CSS类变化的效果:
import { useRef, useState } from "react"; import "./Navbar1.css"; import QueensLogoH from "./NavbarAssets/queens-logo-horizontal.png"; export default function App() { const [isActive, setIsActive] = useState(false); const mainListDivRef = useRef(null); function onClickNavTrigger() { setIsActive((a) => !a); const mainListDivEl = mainListDivRef.current; mainListDivEl.classList.toggle("show_list"); } return ( <> <nav className="nav"> <div className="container"> <div className="logo"> <a href="#"> <img src={QueensLogoH} height="80"></img> </a> </div> <div id="mainListDiv" className="main_list" ref={mainListDivRef}> <ul className="navlinks"> <li> <a href="#">About</a> </li> <li> <a href="#">Portfolio</a> </li> <li> <a href="#">Services</a> </li> <li> <a href="#">Contact</a> </li> </ul> </div> <span className={`navTrigger ${isActive ? "active" : ""}`} onClick={onClickNavTrigger}> <i></i> <i></i> <i></i> </span> </div> </nav> <section className="home"></section> <div style={{ height: "1000px" }}> <h2 className="myH2">What is this ?</h2> <p className="myP">This is a responsive fixed navbar animated on scroll</p> <p className="myP"> I took inspiration from ABDO STEIF and Dicson </p> <p className="myP">I HOPE YOU FIND THIS USEFULL</p> <p className="myP">Albi</p> <p className="myP">random text</p> </div> </> ); }
解决方案
通过React的状态管理和副作用监听即可实现该效果,步骤如下:
- 新增状态变量管理导航栏状态
添加isNavAffixed状态,标记是否需要给导航栏添加affix类:
const [isNavAffixed, setIsNavAffixed] = useState(false);
- 使用
useEffect监听滚动事件
组件挂载时添加滚动监听,判断滚动距离并更新状态;组件卸载时移除监听避免内存泄漏:
useEffect(() => { const handleScroll = () => { const shouldAffix = window.scrollY > 50; setIsNavAffixed(shouldAffix); if (shouldAffix) console.log("OK"); }; window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, []);
注意需要导入useEffect:import { useRef, useState, useEffect } from "react";
- 动态绑定导航栏的className
将导航栏的className改为动态拼接,根据状态决定是否添加affix类:
<nav className={`nav ${isNavAffixed ? 'affix' : ''}`}>
修改后的完整代码
import { useRef, useState, useEffect } from "react"; import "./Navbar1.css"; import QueensLogoH from "./NavbarAssets/queens-logo-horizontal.png"; export default function App() { const [isActive, setIsActive] = useState(false); const [isNavAffixed, setIsNavAffixed] = useState(false); const mainListDivRef = useRef(null); function onClickNavTrigger() { setIsActive((a) => !a); const mainListDivEl = mainListDivRef.current; mainListDivEl.classList.toggle("show_list"); } useEffect(() => { const handleScroll = () => { const shouldAffix = window.scrollY > 50; setIsNavAffixed(shouldAffix); if (shouldAffix) console.log("OK"); }; window.addEventListener("scroll", handleScroll); return () => window.removeEventListener("scroll", handleScroll); }, []); return ( <> <nav className={`nav ${isNavAffixed ? 'affix' : ''}`}> <div className="container"> <div className="logo"> <a href="#"> <img src={QueensLogoH} height="80"></img> </a> </div> <div id="mainListDiv" className="main_list" ref={mainListDivRef}> <ul className="navlinks"> <li> <a href="#">About</a> </li> <li> <a href="#">Portfolio</a> </li> <li> <a href="#">Services</a> </li> <li> <a href="#">Contact</a> </li> </ul> </div> <span className={`navTrigger ${isActive ? "active" : ""}`} onClick={onClickNavTrigger}> <i></i> <i></i> <i></i> </span> </div> </nav> <section className="home"></section> <div style={{ height: "1000px" }}> <h2 className="myH2">What is this ?</h2> <p className="myP">This is a responsive fixed navbar animated on scroll</p> <p className="myP"> I took inspiration from ABDO STEIF and Dicson </p> <p className="myP">I HOPE YOU FIND THIS USEFULL</p> <p className="myP">Albi</p> <p className="myP">random text</p> </div> </> ); }
内容的提问来源于stack exchange,提问作者Soccerball123
相关产品推荐
相关产品推荐

