首页 > web前端 > js教程 > 正文

基于滚动速度控制导航栏可见性的React Hook优化教程

霞舞
发布: 2025-08-19 17:02:01
原创
791人浏览过

基于滚动速度控制导航栏可见性的react hook优化教程

本文将介绍如何创建一个React Hook,用于根据滚动位置、滚动方向和滚动速度来控制导航栏的可见性,实现类似Humboldt forum网站的交互效果。我们将详细分析原始Hook的实现,并提供优化后的版本,重点关注性能提升,包括使用useCallback进行函数记忆,以及依赖项的合理设置,确保Hook在必要时才更新。

创建基于滚动速度的导航栏可见性控制Hook

在Web开发中,根据用户的滚动行为动态调整导航栏的可见性是一种常见的交互模式,能够提升用户体验。本教程将引导你创建一个React Hook,实现以下功能:

  1. 导航栏初始时固定在页面顶部。
  2. 当用户向下滚动时,隐藏导航栏。
  3. 当用户向上快速滚动时,重新显示导航栏。
  4. 导航栏始终在页面顶部可见。

原始Hook的实现与分析

以下是原始Hook的代码:

const useScrollSpeed = (navHeight: number, maxScrollSpeed: number) => {

  const [lastScrollTime, setLastScrollTime] = useState(new Date().getTime());
  const [currentScrollPos, setCurrentScrollPos] = useState(0)
  const [prevScrollPos, setPrevScrollPos] = useState(0);
  const [visible, setVisible] = useState(true);

  const handleScroll = () => {
    const distance = Math.abs(currentScrollPos - prevScrollPos);
    const scrollSpeed = distance / (new Date().getTime() - lastScrollTime);


      if (currentScrollPos > prevScrollPos) {
        setVisible(false);
      } else {
        if (scrollSpeed > maxScrollSpeed) {
          setVisible(true);
        }
      }

    setPrevScrollPos(currentScrollPos);
    setLastScrollTime(new Date().getTime());
  };

  if (typeof window !== "undefined") {
    useEffect(() => {
      setCurrentScrollPos(window.scrollY)

      if (currentScrollPos < navHeight) {
        setVisible(true);
      } 
      window.addEventListener("scroll", handleScroll);
      return () => window.removeEventListener("scroll", handleScroll);
    }, [window.scrollY]);
  }


  return visible;
};
export default useScrollSpeed;
登录后复制

这段代码存在一些潜在的性能问题:

  • handleScroll函数在每次滚动事件触发时都会重新创建,导致不必要的函数重新渲染。
  • useEffect的依赖项window.scrollY会导致每次滚动都会触发useEffect,这可能会导致性能问题。

优化后的Hook实现

为了解决上述问题,我们可以使用useCallback来记忆handleScroll函数,并优化useEffect的依赖项。

先见AI
先见AI

数据为基,先见未见

先见AI 95
查看详情 先见AI
import { useState, useEffect, useCallback } from 'react';

const useScrollSpeed = (navHeight: number, maxScrollSpeed: number) => {
  const [lastScrollTime, setLastScrollTime] = useState(new Date().getTime());
  const [currentScrollPos, setCurrentScrollPos] = useState(0);
  const [prevScrollPos, setPrevScrollPos] = useState(0);
  const [visible, setVisible] = useState(true);

  const handleScroll = useCallback(() => {
    const now = new Date().getTime();
    const distance = Math.abs(currentScrollPos - prevScrollPos);
    const scrollSpeed = distance / (now - lastScrollTime);

    if (currentScrollPos > prevScrollPos) {
      setVisible(false);
    } else {
      if (scrollSpeed > maxScrollSpeed) {
        setVisible(true);
      }
    }

    setPrevScrollPos(currentScrollPos);
    setLastScrollTime(now);
  }, [currentScrollPos, prevScrollPos, lastScrollTime, setVisible, maxScrollSpeed]);

  useEffect(() => {
    const handleInitialScroll = () => {
      setCurrentScrollPos(window.scrollY);
      if (window.scrollY < navHeight) {
        setVisible(true);
      }
    };

    handleInitialScroll(); // 初始化滚动位置和可见性

    window.addEventListener('scroll', handleScroll);
    return () => window.removeEventListener('scroll', handleScroll);
  }, [handleScroll, navHeight]);

  return visible;
};

export default useScrollSpeed;
登录后复制

优化说明:

  1. useCallback: 使用 useCallback 包裹 handleScroll 函数。这确保了只有当依赖项(currentScrollPos,prevScrollPos,lastScrollTime,setVisible,maxScrollSpeed)发生变化时,handleScroll 函数才会被重新创建。
  2. useEffect依赖项优化: 移除了window.scrollY作为useEffect的依赖项。取而代之的是,在useEffect内部添加了一个handleInitialScroll函数来初始化滚动位置和可见性,并只在组件挂载时执行一次。
  3. 代码可读性: 使用 now 变量存储当前时间,避免多次调用 new Date().getTime(),提高代码可读性。

使用示例

import useScrollSpeed from './useScrollSpeed';
import React, { useState, useEffect } from 'react';

const Navbar = () => {
  const navHeight = 60; // 导航栏高度
  const maxScrollSpeed = 0.5; // 最大滚动速度,用于判断是否快速向上滚动
  const isVisible = useScrollSpeed(navHeight, maxScrollSpeed);
  const [style, setStyle] = useState({
    top: 0,
    transition: 'top 0.3s',
    position: 'fixed',
    width: '100%',
    backgroundColor: 'white',
    zIndex: 1000
  });

  useEffect(() => {
    setStyle(prevStyle => ({
      ...prevStyle,
      top: isVisible ? 0 : `-${navHeight}px`
    }));
  }, [isVisible, navHeight]);


  return (
    <nav style={style}>
      {/* 导航栏内容 */}
      <h1>My Website</h1>
    </nav>
  );
};

export default Navbar;
登录后复制

在这个例子中,Navbar 组件使用 useScrollSpeed Hook 来判断导航栏是否应该可见。根据 isVisible 的值,动态地设置导航栏的 top 样式,实现显示和隐藏的动画效果。

注意事项

  • navHeight 和 maxScrollSpeed 的值需要根据实际情况进行调整。
  • 在复杂的应用中,可以考虑使用节流或防抖技术来进一步优化滚动事件的处理。
  • 确保在组件卸载时移除事件监听器,避免内存泄漏。

总结

通过使用 useCallback 和优化 useEffect 的依赖项,我们可以显著提升基于滚动速度控制导航栏可见性的React Hook的性能。优化后的Hook减少了不必要的函数重新创建和组件重新渲染,从而提高了应用的整体性能和用户体验。希望本教程能够帮助你更好地理解和应用React Hook。

以上就是基于滚动速度控制导航栏可见性的React Hook优化教程的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号