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

前言:

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

1.安装react-scroll-to 

npm install react-scroll-to

2.封装 useScrollIntoView钩子

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.在页面中使用

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;

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值