[원티드 프리온보딩] TIL - (4)

5월 6일

마우스 클릭 & 드래그로 스크롤 구현하기

요소들이 상하로 정렬되는 것이 아닌 좌우로 정렬돼있을 시 스크롤이 좌우로 생길 수 있다.
그러한 경우 마우스로는 스크롤하기가 불편한데, 이러한 경우를 위해 마우스 클릭과 드래그로 스크롤을 구현하였다.

const containerRef = useRef();

let position = { left: 0, x: 0 };
const onMouseMove = (e) => {
  const x = e.clientX - position.x;

  containerRef.current.scrollLeft = position.left - x;
};

const onMouseUp = () => {
  containerRef.current.style.cursor = "grab";
  document.removeEventListener("mousemove", onMouseMove);
  document.removeEventListener("mouseup", onMouseUp);
};

const onMouseDown = (e) => {
  position = {
    left: containerRef.current.scrollLeft,
    x: e.clientX,
  };
  containerRef.current.style.cursor = "grabbing";
  document.addEventListener("mousemove", onMouseMove);
  document.addEventListener("mouseup", onMouseUp);
};

return (
  <div
    ref={containerRef}
    role="none"
    className={styles.container}
    onMouseDown={onMouseDown}
  >
    <ul>
      <li>1</li>
      <li>2</li>
      <li>3</li>
      <li>4</li>
      <li>5</li>
    </ul>
  </div>
);

총 코드는 이러하다.

파헤치기

const containerRef = useRef();

스크롤을 적용할 컨테이너 ref다.

let position = { left: 0, x: 0 };

컨테이너의 스크롤 위치와 이벤트가 발생한 마우스의 위치를 판별할 객체이다.

const onMouseDown = (e) => {
  position = {
    left: containerRef.current.scrollLeft,
    x: e.clientX,
  };
  containerRef.current.style.cursor = "grabbing";
  document.addEventListener("mousemove", onMouseMove);
  document.addEventListener("mouseup", onMouseUp);
};

마우스를 누르는 순간 position에 대한 값을 설정하고, 마우스를 움직일 때와 뗏을 때의 이벤트 리스너를 추가한다.

const onMouseMove = (e) => {
  const x = e.clientX - position.x;

  containerRef.current.scrollLeft = position.left - x;
};

마우스의 움직임에 따라 마우스가 눌린 위치로부터 얼마나 이동했는지를 구하고, 그 값으로 컨테이너의 스크롤 위치를 변경시켜준다.

const onMouseUp = () => {
  containerRef.current.style.cursor = "grab";
  document.removeEventListener("mousemove", onMouseMove);
  document.removeEventListener("mouseup", onMouseUp);
};

마우스를 떼는 순간 마우스를 눌렀을 때 추가된 이벤트 리스너를 모두 제거한다.

여담

자바스크립트만을 사용해 구현하였지만 나중에는 라이브러리를 활용해봐도 좋을 것 같다.