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;
相关推荐
jin12332226 分钟前
基于React Native鸿蒙跨平台地址管理是许多电商、外卖、物流等应用的重要功能模块,实现了地址的添加、编辑、删除和设置默认等功能
javascript·react native·react.js·ecmascript·harmonyos
2501_920931701 小时前
React Native鸿蒙跨平台医疗健康类的血压记录,包括收缩压、舒张压、心率、日期、时间、备注和状态
javascript·react native·react.js·ecmascript·harmonyos
落霞的思绪1 小时前
配置React和React-dom为CDN引入
前端·react.js·前端框架
Hacker_Z&Q1 小时前
CSS 笔记2 (属性)
前端·css·笔记
Anastasiozzzz1 小时前
LeetCode Hot100 295. 数据流的中位数 MedianFinder
java·服务器·前端
橙露2 小时前
React Hooks 深度解析:从基础使用到自定义 Hooks 的封装技巧
javascript·react.js·ecmascript
Exquisite.2 小时前
Nginx
服务器·前端·nginx
2501_920931702 小时前
React Native鸿蒙跨平台使用useState管理健康记录和过滤状态,支持多种健康数据类型(血压、体重等)并实现按类型过滤功能
javascript·react native·react.js·ecmascript·harmonyos
打小就很皮...2 小时前
dnd-kit 实现表格拖拽排序
前端·react.js·表格拖拽·dnd-kit
Ulyanov2 小时前
从静态到沉浸:打造惊艳的Web技术发展历程3D时间轴
前端·javascript·html5·gui开发