반응: 매우 간단한 부드러운 스크롤링

나는 내 포트폴리오를 다시 만들고 싶었고, 내가 원했던 주요 사항 중 하나는 부드러운 스크롤링이었습니다. 그래서 추가 종속성 없이 반응하는 아주 간단한 부드러운 스크롤 효과를 만들었습니다.

이 블로그에서 우리는 그것을 함께 만들 것입니다. 그럼 바로 들어가 보겠습니다.

Live Link

CodeSandBox

Github Repo

설정



다음 명령어를 실행하여 반응 앱을 설정합니다.

npx create-react-app smooth-scroll
cd smooth-scroll
yarn start


개요



따라서 본질적으로 우리가 하려고 하는 것은 단순히 지연을 사용하여 Y 방향으로 div를 변환하는 것입니다.
이 div는 전체 SPA(단일 페이지 응용 프로그램)를 유지하므로 전체적으로 부드러운 스크롤 효과가 나타납니다.

<div className="parent">
  <div ref={scrollingContainer}>
    {/* The Complete App */}
  </div>
</div



.parent{
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  pointer-events: none;
}


이 설정에서 refscrollingContainer가 있는 div는 Y 방향으로 변환됩니다.
"parent"클래스가 있는 div는 position: fixed 로 설정되어 있습니다. 이것은 필수적입니다. 그렇지 않으면 하위 div가 아래 공간을 비워두고 번역됩니다.

이렇게 함으로써 우리는 기본적으로 전체 앱이 스크롤 및 기타 요소가 없는 "width=100%"및 "height=100%"의 고정 컨테이너임을 브라우저에 알립니다.

나중에 태그 높이를 "scrollingContainer div"와 같게 설정하면 스크롤할 수 있습니다.

스크롤에서 "scrollingContainer div"를 번역합니다.

이것이 말이 되지 않더라도 걱정하지 마십시오. 코드가 더 명확해지기를 바랍니다.

최종 파일 구조




SmoothScroll.js


src/components/SmoothScroll/SmoothScroll.js에 파일을 생성하고 아래 코드를 붙여넣습니다.
아직 수입품에 대해 걱정하지 마십시오. 곧 생성하겠습니다.

import React, { useEffect, useRef } from "react";

import "./SmoothScroll.css";
import useWindowSize from "../../hooks/useWindowSize";

const SmoothScroll = ({ children }) => {
  // 1.
  const windowSize = useWindowSize();

  //2.
  const scrollingContainerRef = useRef();

  // 3.
  const data = {
    ease: 0.1,
    current: 0,
    previous: 0,
    rounded: 0,
  };

  // 4.
  useEffect(() => {
    setBodyHeight();
  }, [windowSize.height]);

  const setBodyHeight = () => {
    document.body.style.height = `${
      scrollingContainerRef.current.getBoundingClientRect().height
    }px`;
  };

  // 5.
  useEffect(() => {
    requestAnimationFrame(() => smoothScrollingHandler());
  }, []);

  const smoothScrollingHandler = () => {
    data.current = window.scrollY;
    data.previous += (data.current - data.previous) * data.ease;
    data.rounded = Math.round(data.previous * 100) / 100;

    scrollingContainerRef.current.style.transform = `translateY(-${data.previous}px)`;

    // Recursive call
    requestAnimationFrame(() => smoothScrollingHandler());
  };

  return (
    <div className="parent">
      <div ref={scrollingContainerRef}>{children}</div>
    </div>
  );
};

export default SmoothScroll;


분해해 봅시다.
  • useWindowSize()는 창의 현재 innerWidth 및 innerHeight를 반환하는 사용자 지정 후크입니다.
  • scrollingContainerRef는 div에 translateY 속성을 즉석에서 적용하는 데 사용됩니다.
  • data는 스크롤할 때마다 반응 구성 요소가 다시 렌더링되는 것을 원하지 않기 때문에 상태가 아닙니다.
  • 이 useEffect는 windowSize가 변경된 경우에만 실행됩니다(사용자가 브라우저의 크기를 조정하는 경우). setBodyHeight 높이 속성을 "scrollingContainerRef div"의 높이와 동일하게 만듭니다. "position: fixed"를 "parent div"에 전달하면 전체 "scrollingContainerRef div"
  • 를 스크롤할 수 있는 충분한 공간이 확보됩니다.
  • 이 useEffect는 한 번만 실행되고 smoothScrolling 함수를 호출합니다.smoothScrolling 함수는 사용자가 스크롤할 때마다 "scrollingContainerRef div"의 번역 속성을 재귀적으로 변경하여 실행됩니다.
  • smoothScrolling 함수를 통해 requestAnimationFrame() 함수를 호출하고 있습니다.

    The window.requestAnimationFrame(**)** method tells the browser that you wish to perform an animation and requests that the browser calls a specified function to update an animation before the next repaint. The method takes a callback as an argument to be invoked before the repaint.

    Note: Your callback routine must itself call requestAnimationFrame() again if you want to animate another frame at the next repaint. requestAnimationFrame() is 1 shot.



    부드러운 스크롤링.css


    src/components/SmoothScroll/SmoothScroll.css에 파일을 생성하고 아래 코드를 붙여넣습니다.

    .parent {
      position: fixed;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      overflow: hidden;
      pointer-events: none;
    }
    


    useWindowSize.js



    src/hooks/useWindowSize.js에 파일을 만들고 아래 코드를 붙여넣습니다.

    import { useState, useEffect } from "react";
    
    export default function useWindowSize() {
      const getSize = () => {
        return {
          width: window.innerWidth,
          height: window.innerHeight,
        };
      };
    
      const [windowSize, setWindowSize] = useState(getSize);
    
      useEffect(() => {
        const handleResize = () => {
          setWindowSize(getSize());
        };
    
        window.addEventListener("resize", handleResize);
        return () => window.removeEventListener("resize", handleResize);
      }, []);
    
      return windowSize;
    }
    


    이것은 창resize의 이벤트를 수신하고 창의 최신innerWidthinnerHeight를 반환하는 매우 간단한 후크입니다.

    섹션.js



    파일src/components/Section/Section.js을 생성하고 아래 코드를 붙여넣습니다.

    import React from "react";
    
    import "./section.css";
    
    const section = ({ flexDirection }) => {
      return (
        <div className="section" style={{ flexDirection: flexDirection }}>
          <div className="left-container">
            <div className="block"></div>
          </div>
    
          <div className="right-container">
            <div className="container">
              <p>
                Lorem ipsum dolor sit amet consectetur adipisicing elit. In
                laudantium esse fugiat illum tempore sapiente soluta labore voluptas
                iusto deleniti ab suscipit dolores quisquam corrupti facilis, id
                temporibus mollitia repellat omnis tempora commodi eveniet.
                Incidunt, perspiciatis, adipisci laboriosam dolores quos dolor
                voluptate odio magnam aperiam, alias asperiores pariatur! Nisi,
                libero!
              </p>
            </div>
          </div>
        </div>
      );
    };
    
    export default section;
    


    부드러운 스크롤링.css



    파일src/components/Section/Section.css을 생성하고 아래 코드를 붙여넣습니다.

    .section {
      display: flex;
      justify-content: space-around;
      width: 100%;
      align-items: center;
      height: 100vh;
    }
    
    .block {
      width: 250px;
      height: 250px;
      padding: 60px;
      background-color: peachpuff;
    }
    
    .container {
      width: 500px;
    }
    
    p {
      font-size: 1.5rem;
    }
    


    스크롤 컨테이너의 일부 공간을 채우기 위한 반응 구성 요소

    앱.js




    import React from "react";
    
    import "./App.css";
    import Section from "./components/Section/Section";
    import SmoothScroll from "./components/SmoothScroll/SmoothScroll";
    
    function App() {
      return (
        <SmoothScroll>
          <h2>Smooth Scrolling</h2>
          <Section flexDirection="row" />
          <Section flexDirection="row-reverse" />
          <Section flexDirection="row" />
          <Section flexDirection="row-reverse" />
          <Section flexDirection="row" />
          <Section flexDirection="row-reverse" />
        </SmoothScroll>
      );
    }
    
    export default App;
    


    앱.css




    h2 {
      text-align: center;
      margin: 40px auto;
      font-size: 4rem;
    }
    


    Live Link

    CodeSandBox

    Github Repo

    읽어 주셔서 감사합니다!



    당신의 생각을 듣고 싶습니다!

    좋은 웹페이지 즐겨찾기