React切换Tab栏并进行锚点滚动

前言:

最近公司有一个功能模块需要实现切换Tab栏之后跳转到对应锚点位置的功能,我研究之后写了一个自定义钩子,现在分享给小伙伴们,有需要可以直接使用提升工作效率。

1.安装react-scroll-to

npm install react-scroll-to

2.封装 useScrollIntoView钩子

javascript 复制代码
import { useRef, useEffect } from "react";

function useScrollIntoView() {
  const targetRef = useRef(null);
  function scrollToTarget() {
    if (targetRef.current) {
//targetRef.current.getBoundingClientRect().top获取当前元素的相对于视口顶部的高度
//document.documentElement.scrollTop:获取整个文档在垂直方向上滚动的距离
      const topPosition =
        targetRef.current.getBoundingClientRect().top +
        document.documentElement.scrollTop;
      window.scrollTo({
        top: topPosition - 49, // 设置距离顶部的偏移量即顶部导航的高度也可以通过getBoundingClientRect获取准确值
        behavior: "smooth",
      });
    }
  }
  useEffect(() => {
    // 在组件挂载后立即滚动到目标元素
    scrollToTarget();
  }, []);

  return {
    targetRef,
    scrollToTarget,
  };
}

export default useScrollIntoView;

3.在页面中使用

javascript 复制代码
import useScrollIntoView from "@utils/useScrollIntoView"; //自定义滚动hook
const [activeTab, setActiveTab] = useState("复习单词");
const TodayToWords = () => {
  const { targetRef: reviewWords, scrollToTarget: scrollToAnchor1 } =
    useScrollIntoView();
  const { targetRef: newWords, scrollToTarget: scrollToAnchor2 } =
    useScrollIntoView();
  const { targetRef: unFinish, scrollToTarget: scrollToAnchor3 } =
    useScrollIntoView();
  //切换tab栏
  const handleTabClick = (tab) => {
    setActiveTab(tab);
    if (tab === "复习单词") {
      scrollToAnchor1();
    } else if (tab === "新学单词") {
      scrollToAnchor2();
    } else if (tab === "未学完单词") {
      scrollToAnchor3();
    }
  };
  const WordList = ({
    words,
    targetRef = null,
  }) => {
 return ({words.length > 0 && (
           <div
                  className={styles["word-item-content"]}
                  onClick={() => {
                     handleGetReviewWordsRead(item, idx);
                    }}
                  >
                    <span className={styles["word"]}>{item.word}</span>
                    <span className={styles["score"]}>
                      {`学习进度${
                        Number(item.score) >= 10
                          ? 100
                          : (Number(item.score) / 10) * 100
                      }%`}
                    </span>
            </div>
      )
   }      
)
return (
       <div className={styles["learn-container"]}>
        <div className={styles["learn-container-tab"]}>
          {reviewFinishedWords.length > 0 && (
            <div
              onClick={() => {
                handleTabClick("复习单词");
              }}
              className={`${
                activeTab === "复习单词" ? styles.active : ""
              }`}
            >
              {textFront.reviewFinishedWords}
            </div>
          )}
          {newFinishedWords.length > 0 && (
            <div
              onClick={() => {
                handleTabClick("新学单词");
              }}
              className={`${
                activeTab === "新学单词" ? styles.active : ""
              }`}
            >
              {textFront.newFinishedWords}
            </div>
          )}
          {unFinishedWords.length > 0 && (
            <div
              onClick={() => {
                handleTabClick("未学完单词");
              }}
              className={`${
                activeTab === "未学完单词" ? styles.active : ""
              }`}
            >
              {textFront.unFinishedWords}
            </div>
          )}
        </div>
        {/* 自定义组件,点击切换Tab栏时的滚动区域 */}
        <WordList
          words={reviewFinishedWords}
          targetRef={reviewWords}
        />
        <WordList
          words={newFinishedWords}
          targetRef={newWords}
        />
        <WordList
          words={unFinishedWords}
          targetRef={unFinish}
        />
      </div>
)
}
export default TodayToWords;
相关推荐
谢尔登1 小时前
【React】setState 的同步异步问题
前端·javascript·react.js
2401_857297911 小时前
招联金融2025秋招倒计时
java·前端·算法·金融·求职招聘
Xerale1 小时前
Laravel Admin 中的 “Array to String Conversion“ 问题及其解决方法
前端·数据库·笔记·php·laravel
探路1 小时前
狂肝两周,写了一个"本地化"的桌面端工具:超级待办
前端·vue.js·后端
温、2 小时前
【音频可视化】通过canvas绘制音频波形图
前端·音视频
王可夫2 小时前
JavaScript基础---typeof和instanceof的区别
开发语言·前端·javascript
程思扬2 小时前
用ChatGPT做数据分析与挖掘,爽!
运维·经验分享·docker·chatgpt·数据挖掘·数据分析·前端框架
我的运维人生2 小时前
Apache服务器深度解析与实践应用:构建高效Web服务的基石
服务器·前端·apache·运维开发·技术共享
合合技术团队2 小时前
OCR+PDF解析配套前端工具开源详解!
前端·深度学习·pdf·ocr