javascript - 如何将元素 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>
)
我目前将屏幕移动到导航栏上单击的类别,当屏幕焦点位于其顶部时如何设置所选类别
解决方案
据我了解,我已尝试回答您的问题。我已经填写了一些额外的部分来帮助提供完整的解决方案。我希望这与您的问题有关!
因此,如果我对您的理解正确,您希望:
- 当用户滚动页面时,能够自动更新导航栏中的活动选项卡。另外,我假设他们正在垂直滚动以获取我的答案。
根据您提供的问题和代码,我推断您的设置有点像这样:
- 包含给定项目内容的部分或类别组件
- 一个页面组件,它将呈现许多类别组件和导航栏
鉴于这两件事,我将以下代码放在一起,可以帮助您实现您正在寻找的功能:
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>
);
}
如果我没有全面了解您的问题,请评论我可能错过的内容,以便我更新我的答案!
参考:
- isElementInFocusArea 函数改编自这里:How can I tell if a DOM element is visible in the current viewport?
- 从这里处理参考列表的灵感:如何使用多个参考用于带有钩子的元素数组?
推荐阅读
- python - Python - 通过随机变量增加时间
- visual-studio-code - VSCode 中的键盘输入块
- python - 从文件标题中提取不同长度数的算法
- javascript - Internet Explorer 中的 Qlik Sense Modal
- selenium - 复选框伪元素的硒选择器
- r - 如何从调查数据中分离出非 0 答案
- android - Error: The method `CircularNotchedRectangle` is not defined
- c# - IEnumerable 在 Array 和 List 上的表现不同
- linq - C# LINQ to SQL - 如何在“...”中替换?
- entity-framework - Xamarin iOS:值不能为空。参数名称:key