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;
相关推荐
嘗_8 分钟前
暑期前端训练day5
前端
uncleTom66615 分钟前
前端布局利器:rem 适配全面解析
前端
谦哥18 分钟前
Claude4免费Vibe Coding!目前比较好的Cursor替代方案
前端·javascript·claude
LEAFF28 分钟前
如何 测试Labview是否返回数据 ?
前端
Spider_Man30 分钟前
🚀 从阻塞到丝滑:React中DeepSeek LLM流式输出的实现秘籍
前端·react.js·llm
心在飞扬32 分钟前
理解JS事件环(Event Loop)
前端·javascript
盏茶作酒291 小时前
打造自己的组件库(一)宏函数解析
前端·vue.js
山有木兮木有枝_1 小时前
JavaScript 设计模式--单例模式
前端·javascript·代码规范
一大树1 小时前
Vue3 开发必备:20 个实用技巧
前端·vue.js
颜渊呐1 小时前
uniapp中APPwebview与网页的双向通信
前端·uni-app