由于这个问题最容易用例子来解释,这里有一个 CodeSandbox 来说明:https://codesandbox.io/s/github/metal450/react-scroll-sticky。该项目使用 React、TailwindCSS 和 react-scroll 构建以实现平滑滚动。
我正在尝试使用粘性导航栏创建链接以在 flexbox 中滚动列/行。只要导航栏相对于 Flexbox 的主轴“粘性”,而不是它的横轴,它就可以很好地工作。在 CodeSandbox 中,如果输出适当宽(也就是在大型设备上),您会看到侧边栏出现在左侧,每个链接都会滚动右侧的列,将其对应的项目与容器顶部对齐.
但是,如果您稍微缩小输出直到看到“小型设备”布局,您将能够看到问题。现在“侧边栏”位于顶部,如果您单击导航按钮,它会滚动以便所选项目隐藏在导航栏后面。
这确实是有道理的:滚动条相对于一个容器滚动,并且该容器的顶部位于粘性导航栏的后面。但是,我想要的结果是单击“项目 1”并使其滚动,以便项目 1 位于可滚动区域的顶部(不隐藏在粘性导航栏下方)。
我对 flexbox 还很陌生,无论我尝试什么,我似乎都无法弄清楚所需的行为。任何帮助将不胜感激。
答案 0 :(得分:2)
扩展@YellowAfterlife 的答案,我会使用 refs 而不是 document.getElementById
。
此外,您只需要“移动”上的偏移量,因此您可以使用 react-responsive
之类的包。
import React, { useRef, useState, useEffect } from "react";
import { Link } from "react-scroll";
import { useMediaQuery } from "react-responsive";
function App() {
const items = ["item1", "item2", "item3", "item4", "item5", "item6", "item7"];
const container = "scrollContainer";
const menuRef = useRef(null);
const [menuHeight, setMenuHeight] = useState(0);
const isMobile = useMediaQuery({
query: "(max-width: 767px)"
});
useEffect(() => {
setMenuHeight(menuRef.current.clientHeight);
}, [menuRef]);
return (
<main className="flex absolute right-0 bottom-0 left-0 top-0">
<div
id={container}
className="md:flex-row flex flex-col overflow-auto border border-box"
style={{ flexBasis: "65%", flex: 2 }}
>
<div
ref={menuRef}
className="md:w-64 p-3 border sticky top-0 flex-shrink-0 bg-white border-box"
>
{items.map((item) => (
<div className="cursor-pointer m-2 underline" key={item}>
<Link
to={item}
smooth={true}
duration={500}
spy={true}
containerId={container}
offset={isMobile ? -menuHeight : null}
>
{item}
</Link>
</div>
))}
</div>
<div style={{ flex: 1 }}>
{items.map((item) => (
<div key={item} id={item} className="h-64 border m-2 bg-gray-100">
{item}
</div>
))}
</div>
</div>
</main>
);
}
export default App;
答案 1 :(得分:1)
react-scroll
supports offset
参数,您可以使用它来动态计算菜单高度:
import { Link } from 'react-scroll';
function App() {
const items = ['item1', 'item2', 'item3', 'item4', 'item5', 'item6', 'item7'];
const container = "scrollContainer";
const menu = "scrollMenu";
function getScrollOffset() {
if (true/* insert a condition for navbar being on top */) {
return -document.getElementById(menu).offsetHeight;
} else return 0;
}
return (
<main className="flex absolute right-0 bottom-0 left-0 top-0">
<div id={container} className="md:flex-row flex flex-col overflow-auto border border-box" style={{ flexBasis: "65%", flex: 2}}>
<div className="md:w-64 p-3 border sticky top-0 flex-shrink-0 bg-white border-box" id={menu}>
{items.map((item) => <div className="cursor-pointer m-2 underline" key={item}>
<Link to={item} smooth={true} duration={500} spy={true} offset={getScrollOffset()} containerId={container}>{item}</Link>
</div>)}
</div>
<div style={{ flex: 1 }}>
{items.map((item) => <div key={item} id={item} className="h-64 border m-2 bg-gray-100" >{item}</div>)}
</div>
</div>
</main>
);
}
export default App;
考虑到滚动已经由 JavaScript 端处理,仅使用 CSS 的解决方案将远没有那么优雅,并且不会提供任何特别的好处。