开发者

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,

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>

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜