粘性 header 滚动隐藏和显示
Sticky header with hide and show on scroll
我有一个由两部分组成的导航栏(navbarTop 和 navbarBottom);当 scrollY 大于 110 时将显示 navbarTop 并且当用户向上滚动时将显示 navbarbottom ,但我的问题是每个组件将在每次滚动后 re-called ,甚至向下滚动,或者当 navbottom 已经存在并且用户向上滚动,它仍然继续调用该组件。
这是代码:
const Navbar: FC = () => {
const [stickyHeader, setStickyHeader] = useState(false);
const [stickyMenu, setStickyMenu] = useState(false);
console.log('navbar')
const [y, setY] = useState(null);
const handleNavigation = useCallback(
(e) => {
const window = e.currentTarget;
if (!stickyMenu) {
if (y > window.scrollY) {
setStickyMenu(true)
// console.log("scrolling up");
}
}
if (!stickyHeader) {
if (window.scrollY >= 110) {
setStickyHeader(true);
}
}
if (stickyHeader) {
if (window.scrollY <= 110) {
setStickyHeader(false);
}
}
if (stickyMenu) {
if (y < window.scrollY) {
setStickyMenu(false)
// console.log("scrolling down");
}
}
setY(window.scrollY);
},
[y, stickyMenu,stickyHeader]
);
useEffect(() => {
window.addEventListener("scroll", handleNavigation);
return () => {
window.removeEventListener("scroll", handleNavigation);
};
}, [handleNavigation, stickyMenu]);
return (
<>
<div className={s.root}>
{stickyHeader === false ? (
<div className='hidden xl:block md:w-auto'>
<NavbarTop sticky={false}/>
<NavbarBottom
sticky={false}/>
</div>
) : (
<div className='absolute hidden xl:block md:w-auto'>
<NavbarTop sticky={true}/>
{stickyMenu &&
<NavbarBottom sticky={true}/>
}
</div>
)}
<SmallNav/>
</div>
</>
)
}
导出默认导航栏
其实我不是很明白你的问题。你说每个组件在每次滚动后都是re-called。当然是re-called对吧?
无论何时滚动,都会更改 stickyHeader
或 stickyMenu
。 React 监听状态变化和 re-renders 组件。这就是 React 的工作原理。
我看到您正在使用 tailwindcss。
可以先用一个useMemo
监听状态然后根据不同的状态return适当的class。这样您就可以避免一遍又一遍地创建 DOM 个节点。我不知道这是否对你有帮助。希望对您有所帮助。
const Navbar: FC = () => {
const [stickyHeader, setStickyHeader] = useState(false);
const [stickyMenu, setStickyMenu] = useState(false);
// console.log('navbar');
const [y, setY] = useState(null);
const handleNavigation = useCallback(
(e) => {
const window = e.currentTarget;
if (!stickyMenu) {
if (y > window.scrollY) {
setStickyMenu(true);
// console.log("scrolling up");
}
}
if (!stickyHeader) {
if (window.scrollY >= 110) {
setStickyHeader(true);
}
}
if (stickyHeader) {
if (window.scrollY <= 110) {
setStickyHeader(false);
}
}
if (stickyMenu) {
if (y < window.scrollY) {
setStickyMenu(false);
// console.log("scrolling down");
}
}
setY(window.scrollY);
},
[y, stickyMenu, stickyHeader],
);
useEffect(() => {
window.addEventListener('scroll', handleNavigation);
return () => {
window.removeEventListener('scroll', handleNavigation);
};
}, [handleNavigation, stickyMenu]);
const stickyClassName = useMemo(() => {
if (stickyHeader) {
return 'sticky top-0 xl:block md:w-auto';
}
return 'xl:block md:w-auto';
}, [stickyHeader]);
return (
<div className="test" style={{ height: 2000 }}>
<div className={stickyClassName}>
<NavbarTop sticky={stickyHeader} />
{stickyMenu && <NavbarBottom sticky={stickyHeader} />}
</div>
<div>SmallNav</div>
</div>
);
};
export default Navbar;
我有一个由两部分组成的导航栏(navbarTop 和 navbarBottom);当 scrollY 大于 110 时将显示 navbarTop 并且当用户向上滚动时将显示 navbarbottom ,但我的问题是每个组件将在每次滚动后 re-called ,甚至向下滚动,或者当 navbottom 已经存在并且用户向上滚动,它仍然继续调用该组件。 这是代码:
const Navbar: FC = () => {
const [stickyHeader, setStickyHeader] = useState(false);
const [stickyMenu, setStickyMenu] = useState(false);
console.log('navbar')
const [y, setY] = useState(null);
const handleNavigation = useCallback(
(e) => {
const window = e.currentTarget;
if (!stickyMenu) {
if (y > window.scrollY) {
setStickyMenu(true)
// console.log("scrolling up");
}
}
if (!stickyHeader) {
if (window.scrollY >= 110) {
setStickyHeader(true);
}
}
if (stickyHeader) {
if (window.scrollY <= 110) {
setStickyHeader(false);
}
}
if (stickyMenu) {
if (y < window.scrollY) {
setStickyMenu(false)
// console.log("scrolling down");
}
}
setY(window.scrollY);
},
[y, stickyMenu,stickyHeader]
);
useEffect(() => {
window.addEventListener("scroll", handleNavigation);
return () => {
window.removeEventListener("scroll", handleNavigation);
};
}, [handleNavigation, stickyMenu]);
return (
<>
<div className={s.root}>
{stickyHeader === false ? (
<div className='hidden xl:block md:w-auto'>
<NavbarTop sticky={false}/>
<NavbarBottom
sticky={false}/>
</div>
) : (
<div className='absolute hidden xl:block md:w-auto'>
<NavbarTop sticky={true}/>
{stickyMenu &&
<NavbarBottom sticky={true}/>
}
</div>
)}
<SmallNav/>
</div>
</>
)
} 导出默认导航栏
其实我不是很明白你的问题。你说每个组件在每次滚动后都是re-called。当然是re-called对吧?
无论何时滚动,都会更改 stickyHeader
或 stickyMenu
。 React 监听状态变化和 re-renders 组件。这就是 React 的工作原理。
我看到您正在使用 tailwindcss。
可以先用一个useMemo
监听状态然后根据不同的状态return适当的class。这样您就可以避免一遍又一遍地创建 DOM 个节点。我不知道这是否对你有帮助。希望对您有所帮助。
const Navbar: FC = () => {
const [stickyHeader, setStickyHeader] = useState(false);
const [stickyMenu, setStickyMenu] = useState(false);
// console.log('navbar');
const [y, setY] = useState(null);
const handleNavigation = useCallback(
(e) => {
const window = e.currentTarget;
if (!stickyMenu) {
if (y > window.scrollY) {
setStickyMenu(true);
// console.log("scrolling up");
}
}
if (!stickyHeader) {
if (window.scrollY >= 110) {
setStickyHeader(true);
}
}
if (stickyHeader) {
if (window.scrollY <= 110) {
setStickyHeader(false);
}
}
if (stickyMenu) {
if (y < window.scrollY) {
setStickyMenu(false);
// console.log("scrolling down");
}
}
setY(window.scrollY);
},
[y, stickyMenu, stickyHeader],
);
useEffect(() => {
window.addEventListener('scroll', handleNavigation);
return () => {
window.removeEventListener('scroll', handleNavigation);
};
}, [handleNavigation, stickyMenu]);
const stickyClassName = useMemo(() => {
if (stickyHeader) {
return 'sticky top-0 xl:block md:w-auto';
}
return 'xl:block md:w-auto';
}, [stickyHeader]);
return (
<div className="test" style={{ height: 2000 }}>
<div className={stickyClassName}>
<NavbarTop sticky={stickyHeader} />
{stickyMenu && <NavbarBottom sticky={stickyHeader} />}
</div>
<div>SmallNav</div>
</div>
);
};
export default Navbar;