首页 > 解决方案 > 如何将元素 ID 放入滚动视图以在导航栏中标记类别

问题描述

我有一个带有类别列表的导航栏,我想根据用户正在查看的内容设置所选类别,但为此我需要获取元素 ID,但这些 ID 是动态设置的。目前我已经有一个设置选择类别的功能,但是它将选择的类别设置为点击,并且我还想在用户滚动时标记选择的类别。

我的代码

 function onHandleClick(props){
        setCurrentCat(props) 
        document.getElementById(props).scrollIntoView();
    }
    return (
        <div className = {Position ? 'navbarContainer navbarContainerScroll':'navbarContainer'}>
            {Categorias.map(item =>(
               <ul>
                   <li className = {item.Cod === currentCat ? 'navbarContainer liSelect' : 'navbarContainer liNormal'}  
                   onClick = {() => onHandleClick(item.Cod) 
                   }>{item.Nome}</li>
               </ul>
            ))}
  
        </div>
    )

我目前将屏幕移动到导航栏上单击的类别,当屏幕焦点位于其顶部时如何设置所选类别

标签: javascriptreactjs

解决方案


据我了解,我已尝试回答您的问题。我已经填写了一些额外的部分来帮助提供完整的解决方案。我希望这与您的问题有关!

因此,如果我对您的理解正确,您希望:

  • 当用户滚动页面时,能够自动更新导航栏中的活动选项卡。另外,我假设他们正在垂直滚动以获取我的答案。

根据您提供的问题和代码,我推断您的设置有点像这样:

  • 包含给定项目内容的部分或类别组件
  • 一个页面组件,它将呈现许多类别组件和导航栏

鉴于这两件事,我将以下代码放在一起,可以帮助您实现您正在寻找的功能:

import React, { useEffect, useRef, useState } from "react";

/** Check if an HTML element is within the main focus region of the page */
function isElementInMainFocusArea(
  element,
  verticalConstrainFactor = 0,
  horizontalConstrainFactor = 0
) {
  const elementRect = element.getBoundingClientRect();

  const documentHeight =
    window.innerHeight || document.documentElement.clientHeight;
  const documentWidth =
    window.innerWidth || document.documentElement.clientWidth;

  // Vertical focus region
  const topFocusPos = documentHeight * verticalConstrainFactor;
  const bottomFocusPos = documentHeight * (1 - verticalConstrainFactor);

  // Horizontal focus region
  const leftFocusPos = documentWidth * horizontalConstrainFactor;
  const rightFocusPos = documentWidth * (1 - horizontalConstrainFactor);

  return (
    elementRect.top >= topFocusPos &&
    elementRect.bottom <= bottomFocusPos &&
    elementRect.left >= leftFocusPos &&
    elementRect.right <= rightFocusPos
  );
}

/** Navigation bar component which will taken in a list of refs.
Each ref must be assigned to or given as a prop to some other section on the page that we want to scroll to. */
function NavBar({ pageSectionRefs, categories }) {
  const [currentCat, setCurrentCat] = useState();

  /** Set up the scroll event listener to update the currentCat whenever we scroll*/
  useEffect(() => {
    window.addEventListener("scroll", handleScroll);
    return () => window.removeEventListener("scroll", handleScroll);
  }, []);

  /** Check all the refs we are to watch to see which one of them is in focus */
  function handleScroll() {
    for (ref in pageSectionRefs.reverse()) {
      if (isElementInMainFocusArea(ref.current)) {
        setCurrentCat(index);
        return; // if two elements are in focus, only the first will be chosen. Could cause a glitch
      }
    }
  }

  // Returns what you were previously returning for this component
  return (
    <div
      className={
        Position ? "navbarContainer navbarContainerScroll" : "navbarContainer"
      }>
      {categories.map((item) => (
        <ul>
          <li
            className={
              item.Cod === currentCat
                ? "navbarContainer liSelect"
                : "navbarContainer liNormal"
            }
            onClick={() => onHandleClick(item.Cod)}>
            {item.Nome}
          </li>
        </ul>
      ))}
    </div>
  );
}

/** The top level component that will be rendering the NavBar and page sections. */
function MyPage() {
  const categories = [];
  const pageSectionRefs = categories.map(() => useRef());

  return (
    <div>
      <NavBar pageSectionRefs={pageSectionRefs} categories={categories} />
      {categories.map((cat, idx) => {
        return (
          <div key={idx} ref={pageSectionRefs[idx]}>
            Section for category {idx}
          </div>
        );
      })}
    </div>
  );
}

如果我没有全面了解您的问题,请评论我可能错过的内容,以便我更新我的答案!

参考:


推荐阅读