본문 바로가기

Programming/웹개발

[React/Nextjs] 스크롤 창 버튼 네비게이션 컴포넌트 만들기

 

웹사이트에서 좌우 스크롤로 넘겨보는 UI는 마우스를 사용하는 사용자 입장에서는 불편할 수도 있습니다.

모바일로 접속하는 사용자에게는 문제가 없겠지만 다양한 사용자에게 동일한 UX를 제공하는 것도 중요합니다.

UI 레이아웃

위 사진과 같이 좌우 화살표로 메인콘텐츠에 있는 스크롤 영역을 제어하는 형태가 되겠습니다.

코드

먼저 전체적인 구조부터 잡아주겠습니다.

ScrollableButtonNav.tsx

import React from "react";

interface ScrollableButtonNavProps {
  children: React.ReactNode;
  className?: string;
}

const ScrollableButtonNav: React.FC<ScrollableButtonNavProps> = ({
  children,
  className,
}) => {

  return (
    <div className={`${className} relative`}>
      <div className="absolute w-[20%] md:w-[10%] flex items-center bottom-0 top-0 justify-center z-10">
        <button>
          <div className="border-solid border-t-2 border-r-2 border-black p-2 -rotate-[135deg]"></div>
        </button>
      </div>
      <div className="flex w-full h-full overflow-x-scroll snap-x snap-mandatory">
        {children}
      </div>
      <div className="absolute w-[20%] md:w-[10%] flex items-center bottom-0 top-0 right-0 justify-center z-10">
        <button>
          <div className="border-solid border-t-2 border-r-2 border-black p-2 rotate-[45deg]"></div>
        </button>
      </div>
    </div>
  );
};

export {ScrollableButtonNav};

해당 부분을 통해 버튼과 이미지 혹은 다른 콘텐츠가 들어갈 공간을 만들어 주었습니다.

이제 메인 파일에서 컴포넌트를 import하여 콘텐츠 공간을 이미지로 채워보도록 하겠습니다.

index.tsx

import Image from "next/image";
import { ScrollableButtonNav } from "./ScrollableButtonNav";

export default function Home() {
  return (
    <div className="w-[500px] h-[300px] m-auto">
      <ScrollableButtonNav className="flex w-full h-full bg-slate-500">
        <>
          <div className="h-full w-full flex-shrink-0 relative snap-center">
            <Image
              src="/pablo - 1.jpeg"
              alt="우리집 애기"
              fill
              style={{ objectFit: "contain" }}
            />
          </div>
          <div className="h-full w-full flex-shrink-0 relative snap-center">
            <Image
              src="/pablo - 2.jpeg"
              alt="우리집 애기"
              fill
              style={{ objectFit: "contain" }}
            />
          </div>
          <div className="h-full w-full flex-shrink-0 relative snap-center">
            <Image
              src="/pablo - 3.jpeg"
              alt="우리집 애기"
              fill
              style={{ objectFit: "contain" }}
            />
          </div>
        </>
      </ScrollableButtonNav>
    </div>
  );
}

저는 가시성을 위해 ScrollableButtonNav 컴포넌트에 className="bg-slate-500"로 배경을 추가해 줬지만 없어도 되는 부분입니다.

그럼 다음과 같이 스크롤이 창과 좌우 버튼이 생기는 것을 볼 수 있습니다.

그럼 이제 버튼에 기능을 추가해보도록 하겠습니다.

ScrollableButtonNav.tsx

...
const ScrollableButtonNav: React.FC<ScrollableButtonNavProps> = ({
  children,
  className,
}) => {
  const containerRef = React.useRef<HTMLDivElement>(null);
  const onClickLeft = () => {
    if (containerRef.current) {
      const container = containerRef.current;
      const scrollAmount = container.clientWidth;
      container.scrollBy({ left: -scrollAmount, behavior: "smooth" });
    }
  };
  const onClickRight = () => {
    if (containerRef.current) {
      const container = containerRef.current;
      const scrollAmount = container.clientWidth;
      container.scrollBy({ left: scrollAmount, behavior: "smooth" });
    }
  }
  ...
  <div ref={containerRef} className="flex w-full h-full overflow-x-scroll snap-x snap-mandatory">
        {children}
  </div>
  ...

좌우 버튼의 기능을 구현해줄 onClickLeft와 onClickRight 함수 두 개를 작성해 줍니다.

또한, 좌/우 이동 간격을 계산하기 위해 children의 parent container에 useRef를 통해 생성한 레퍼런스를 할당해 줍니다.

마지막으로 버튼에 함수를 할당해 줍니다.

ScrollableButtonNav.tsx

...
<button onClick={onClickLeft}>
  <div className="border-solid border-t-2 border-r-2 border-black p-2 -rotate-[135deg]"></div>
</button>
...
<button onClick={onClickRight}>
  <div className="border-solid border-t-2 border-r-2 border-black p-2 rotate-[45deg]"></div>
</button>
...

그럼 스크롤도 가능하지만 버튼으로 좌우 조작이 가능한 UI가 완성이 됩니다.

(feat. 고양이 pablo)