How to move scroll Y axis regardless of device height in reactjs?
I make 1 component which has 4 sections in vertical.
And if I click menu located on top I want to make scroll move to each section.
For example,
- c开发者_开发知识库lick menu 1 -> section 1
- click menu 2 -> section 2
- click menu 3 -> section 3
For this, I get Y value of each section by useScroll
of framer-motion.
And if I click certain menu, I make window.location
move to that Y value.
But the problem is if I look this homepage on cell phone, not desktop, since device height changes, sections' Y value also changes.
So even if it moves to Y value of section 2 of device 1, in device2, scroll points different section.
So How to make this function regardless of different device height?
I also tried to use Route path
as separating each section by having different route.
But I couldn't differentiate component's route path in one page.
const { scrollY } = useScroll();
const [ychange, setYchange] = useState(0);
useEffect(() => {
scrollY.onChange(() => {
setYchange(scrollY.get());
});
}, [scrollY]);
<NavItem
onClick={() => {
navigate("/");
setTimeout(() => {
window.scrollTo({ top: 5235, behavior: "smooth" });
});
}}
>
<AppText page={page} ychange={ychange} location={location}>
앱 소개
</AppText>
{page === "app" ||
(location === "/" && ychange >= 5234 && ychange < 10336) ? (
<NavBottom />
) : null}
</NavItem>
It seems that element.scrollIntoView()
might be a good fit if this is the use case:
- click menu 1 -> section 1
- click menu 2 -> section 2
- click menu 3 -> section 3
A possible implement is to make a reference for each section
to be scrolled to with useRef
, and call scrollIntoView()
on the referenced element.
More about element.scrollIntoView()
Optional: an offset area from the top of the element when scrolled to can be specified with scroll-margin-top
in styles.
More about scroll-margin-top
Here is a basic example of this implemented. It runs in the snippet for convenience and works better when viewing in full page.
Not sure if this approach would work well in the actual project since posted code is partial, but hope this could still help as a reference.
const { useRef } = React;
const App = () => {
const sectionsRef = useRef([]);
const handleScrollTo = (index) => {
if (!sectionsRef.current[index]) return;
sectionsRef.current[index].scrollIntoView({ behavior: "smooth" });
};
return (
<div className="App">
<nav>
{[1, 2, 3, 4].map((item, index) => (
<button key={item} onClick={()=>handleScrollTo(index)}>{`Section ${item}`}</button>
))}
</nav>
{[1, 2, 3, 4].map((item, index) => (
<section key={item} ref={(element) => (sectionsRef.current[index] = element)}>
<h3>{`This is section ${item}`}</h3>
</section>
))}
</div>
);
};
const root = ReactDOM.createRoot(document.getElementById("root")).render(
<App />
);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
nav,
section,
button {
display: flex;
justify-content: center;
align-items: center;
}
nav {
position: sticky;
top: 0;
padding: 6px;
width: 100%;
height: 50px;
background-color: lightpink;
gap: 12px;
}
button {
padding: 6px;
}
section {
scroll-margin-top: 50px;
width: 100%;
min-height: 100vh;
background-color: lightgreen;
}
section:nth-of-type(1) {
background-color: lightblue;
}
section:nth-of-type(2) {
background-color: lightgreen;
}
section:nth-of-type(3) {
background-color: purple;
}
section:nth-of-type(4) {
background-color: gold;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
精彩评论