使用粘性导航栏自动滚动 Flexbox 列
Posted
技术标签:
【中文标题】使用粘性导航栏自动滚动 Flexbox 列【英文标题】:Auto-Scrolling A Flexbox Column With A Sticky NavBar 【发布时间】:2021-07-28 07:04:27 【问题描述】:因为这个问题最容易用一个例子来解释,这里有一个 CodeSandbox 来说明:https://codesandbox.io/s/github/metal450/react-scroll-sticky。该项目使用 React、TailwindCSS 和 react-scroll 构建,以实现平滑滚动。
我正在尝试使用粘性导航栏创建链接以滚动弹性框中的列/行。只要导航栏相对于 Flexbox 的主轴而不是其横轴是“粘性的”,它就可以很好地工作。在 CodeSandbox 中,如果输出的宽度合适(也就是在大型设备上),您会看到侧边栏出现在左侧,并且每个链接都会滚动右侧的列,将其对应的项目与容器的顶部对齐.
但是,如果您稍微缩小输出直到看到“小型设备”布局,您将能够看到问题所在。现在“侧边栏”位于顶部,如果您单击导航按钮,它将滚动以使所选项目隐藏在导航栏后面。
这确实有些道理:滚动条相对于容器滚动,并且该容器的顶部位于粘性导航栏的后面。但是,我想要的结果是单击“项目 1”并使其滚动,以便项目 1 位于 可滚动区域的顶部(不隐藏在粘性导航栏下方)。
我对弹性盒相当陌生,无论我尝试什么,我似乎都无法弄清楚所需的行为。任何帮助将不胜感激。
【问题讨论】:
【参考方案1】:扩展 @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;
这里是codesandbox
【讨论】:
很好的解决方案!我不知道反应响应,在我的工具箱中肯定很方便:) 一个问题:使用带有 menuRef 的 useEffect 将 clientHeight 放入状态变量有什么好处,而不仅仅是指 menuRef.clientHeight.clientHeight滚动时直接? 我最终做了类似的事情:function getScrollOffset() if (window.getComputedStyle(menuRef.current?.parentElement).flexDirection === 'column') return -menuRef.current?.clientHeight || 0; return -gymCardOffset;
【参考方案2】:
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 的解决方案将远没有那么优雅并且没有特别的好处。
【讨论】:
我想过那样做,但感觉那样更老套,我可能只是忽略了“正确”的纯 CSS 方法(同样没有使用弹性框的经验)。如果纯 CSS 的方式实际上没有你说的那么优雅,那么也许我的第一个想法实际上是正确的方法! ...其实,看起来还是有特点的。单击滚动按钮后,只需将鼠标悬停在浏览器的滚动条上 - 突然当前滚动位置指示器“跳”到不同的位置。又名浏览器认为它已滚动到某个位置,然后当您将鼠标悬停在其滚动条上时,它会更改。让我知道这是 unlcear 或者如果你没有看到它,我会发布一个视频。 我不认为我在 Edge 91 上看到了这个 - 滚动条在制作动画时和之后似乎都按预期工作 有趣。我在 Linux 上的 Firefox 84 上,滚动条肯定表现得很古怪。在“大型设备模式”中它是可以预测的,但在“小型模式”(也就是本期的主题)中,无论我是否使用偏移量,滚动条都会以一种奇怪的方式跳跃,这使得它看起来有问题。以上是关于使用粘性导航栏自动滚动 Flexbox 列的主要内容,如果未能解决你的问题,请参考以下文章