[React] 마우스 드래그로 스크롤 구현하기 - 라이브러리 X
본문 바로가기
더 알아보기/기능

[React] 마우스 드래그로 스크롤 구현하기 - 라이브러리 X

by 은돌1113 2022. 7. 14.
 

[React] 마우스로 드래그 스크롤 구현하기

마우스 버튼을 누르거나 터치하여 스크롤을 구현하는 React 컴포넌트 - wenyanet 인디아나 드래그 스크롤 반응 드래그시 스크롤 구현 예제 / 샌드 박스 여행에 오신 것을 환영합니다! 직접 시도해보

eundol1113.tistory.com

이전에 react-indiana-drag-scroll 라이브러리를 사용하여 구현한 마우스 드래그 스크롤 기능에는 치명적인 문제가 있었다..

바로 input 태그가 동작하지 않는다는 문제였는 데 이와 관련해서 메일도 보내 보았지만 답장을 받지 못해서 반쯤 포기하고 있다가 라이브러리 없이 js를 이용하여 마우스 드래그 스크롤을 구현한 블로그를 발견했다.


아직 코드를 이해하는 중이라 자세한 설명은 여기를 보는 게 좋을 것 같다.

 

Click and Drag to Scroll

웹서핑을 하다보면, 마우스로 드래그해서 스크롤을 할 수 있게끔 해 놓은 페이지들을 종종 볼 수 있다. 마치 터치를 하는 것과 비슷한 조작감을 주곤 하는데, 오늘은 이 드래그 스크롤을 구현해

iborymagic.tistory.com


아래 코드는 위 블로그 코드를 기반으로 해서 약간의 변형과 결과물이다!

 

/components/layout/WidthScroll.js 파일을 만들어서 아래 코드를 삽입 해줬다.

 

여기에서 원본 코드 + 약간의 변형이 들어갔다.

 

1) document

기존 코드에서는 JS 버전이라서 document를 아래와 같이 사용하시는 데

const slider = document.querySelector('.items');

 React나 Next.js에서는 이렇게 쓰면 오류가 발생한다. (해결 방법은 아래 참고)

 

[Error] document is not defined

React나 Next.js와 같은 언어에서 document를 사용하면 아래와 같이 document를 찾을 수 없다는 오류가 발생한다. const slider = document.querySelector(".items"); React나 Next.js와 같은 프로그래밍 언어는..

eundol1113.tistory.com

 

2) pointer

기능 자체가 마우스 클릭으로 드래그를 하는 건데 클릭을 해도 시각적으로 변화가 없길래 아래와 같이 CSS 추가 해주고

.pointer {
  cursor: pointer;
}

 

addEventListener 콜백 함수 안에 삭제/추가 해줬다.
- mousedown, mouseleave, mouseup > slider.classList.remove("pointer");

- mousemove > slider.classList.add("pointer");

 

👉 전체 코드

더보기
const WidthScroll = ({ children }) => {
  let slider = "";
  if (typeof document !== "undefined") {
    slider = document.querySelector(".items");
  }

  let isDown = false;
  let startX;
  let scrollLeft;

  if (slider) {
    slider.addEventListener("mousedown", (e) => {
      isDown = true;
      slider.classList.add("active");
      startX = e.pageX - slider.offsetLeft;
      scrollLeft = slider.scrollLeft;

      // 나머지 경우에는 마우스 포인터 삭제
      slider.classList.remove("pointer");
    });

    slider.addEventListener("mouseleave", () => {
      isDown = false;
      slider.classList.remove("active");

      // 나머지 경우에는 마우스 포인터 삭제
      slider.classList.remove("pointer");
    });

    slider.addEventListener("mouseup", () => {
      isDown = false;
      slider.classList.remove("active");

      // 나머지 경우에는 마우스 포인터 삭제
      slider.classList.remove("pointer");
    });

    slider.addEventListener("mousemove", (e) => {
      if (!isDown) return;
      e.preventDefault();
      const x = e.pageX - slider.offsetLeft;
      const walk = x - startX;
      slider.scrollLeft = scrollLeft - walk;

      // 마우스를 눌러서 드래그 스크롤 할 때만 cursor pointer 설정
      slider.classList.add("pointer");
    });
  }

  return <div>{children}</div>;
};

export default WidthScroll;

/pages/test2.js 파일을 만들어서 테스트 해줬다.

👉 전체 코드

더보기
import WidthScroll from "@/components/layout/WidthScroll";

const Test2 = () => {
  return (
    <WidthScroll>
      <div className="items">
        <div class="item item1">01</div>
        <div class="item item2">02</div>
        <div class="item item3">03</div>
        <div class="item item4">04</div>
        <div class="item item5">05</div>
        <div class="item item6">06</div>
        <div class="item item7">07</div>
        <div class="item item8">08</div>
        <div class="item item9">09</div>
        <div class="item item10">10</div>
        <div class="item item11">11</div>
        <div class="item item12">12</div>
        <div class="item item13">13</div>
        <div class="item item14">14</div>
        <div class="item item15">15</div>
        <div class="item item16">16</div>
        <div class="item item17">17</div>
        <div class="item item18">18</div>
        <div class="item item19">19</div>
        <div class="item item20">20</div>
        <div class="item item21">21</div>
        <div class="item item22">22</div>
        <div class="item item23">23</div>
        <div class="item item24">24</div>
        <div class="item item25">25</div>
      </div>
    </WidthScroll>
  );
};

export default Test2;

약간의 CSS

👉 전체 코드

더보기
.items {
  display: flex;
  width: 500px;
  overflow: scroll;
}

.items .item {
  width: 200px;
  height: 500px;
  border: 1px solid tomato;
}

결과

댓글