Wesbos - 드래그 슬라이드


완성본 예시

내가 디스트리 프로젝트에서 꽤나 애먹었던 기능이다.
여러 웹사이트에서 볼 수 있는 드래그가 가능한 이미지 슬라이더를 구현해보는 챕터다.


로직

  1. const와 addEventListener 선언
  2. mousedown이 true일 때만 mousemove function 실행되도록 설정
  3. 마우스가 클릭 후 시작점 & 드래그된 이동값 출력하기
  4. 마우스가 드래그 된 만큼 item들 움직이기
  5. (부가적 기능) CSS적용해서 시각적 효과 더 입히기

const와 addEventListener 선언

💡 mousedown, mouseup, mousemove, mouseleave를 사용하면 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const slider = document.querySelector('.items');

// 다 한 번씩 찍어보기~

slider.addEventListener('mousedown', () => {
console.log('Down!');
});
slider.addEventListener('mouseup', () => {
console.log('up!');
});
slider.addEventListener('mousemove', () => {
console.log("It's moving!");
});
slider.addEventListener('mouseleave', () => {
console.log('Leaved!');
});

콘솔 확인


mousedown이 true일 때만 mousemove 함수 실행!

💡 드래그의 기본 동작 방식은 “클릭 → 마우스움직이기” 이므로 mousedown이 발생하지 않았을 때에는 mousemove에 대한 함수가 실행돼선 안된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let isDown = false;

slider.addEventListener('mousedown', () => {
isDown = true; // 클릭됐을 때 true 적용
console.log('Down!');
});

slider.addEventListener('mouseup', () => {
isDown = false; // 당연히 마우스업 됐을 때에는 isDown이 false처리!
console.log('up!');
});

slider.addEventListener('mousemove', () => {
if (!isDown) return; // 클릭이 안됐을 때에는 isDown이 false이므로 return된다.
console.log("It's moving!");
});

mousedown 후 마우스 위치와 이동된 값 출력하기

💡 pageX,Y = 브라우저 내에서의 XY좌표를 반환하지만, 스크롤 화면을 포함해 계산한다.
offsetX,Y = 이벤트 대상 객체가 기준이 되어 상대적 마우스 XY좌표를 반환

1
2
3
4
5
6
slider.addEventListener('mousedown', (e) => {
isDown = true;
console.log(e.pageX);
console.log(slider.offsetLeft); // slider박스 옆에 엘리먼트가 추가되거나 마진이 생겼을 때를 대비
console.log(slider.scrollLeft); // 얼마나 움직였는지!
});

콘솔값 확인

이러한 첫 클릭 시의 마우스 위치마우스를 움직인 만큼의 값을 변수화 하여 저장!

1
2
3
4
5
6
7
8
9
10
11
// 미리 변수화!
let startX;
let scrollLeft;

slider.addEventListener('mousedown', (e) => {
isDown = true;
startX = e.pageX - slider.offsetLeft;
scrollLeft = slider.scrollLeft;
console.log(startX);
console.log(scrollLeft);
});

마우스가 드래그 된 만큼 스크롤

💡 scrollLeft = 오른쪽 또는 왼쪽으로 스크롤된 만큼의 값을 반환하거나, 이동하도록 명령할 수 있음

scroll값 예시

1
2
3
4
5
6
7
8
slider.addEventListener('mousemove', (e) => {
if (!isDown) return;
e.preventDefault();
const moved = e.pageX - slider.offsetLeft; // 마우스가 움직인 상대값
const walk = (moved - startX) * 2; // 실제로 마우스를 움직인 절대적 값
slider.scrollLeft = scrollLeft - walk;
// scrollLeft에서 walk를 빼주는 이유 : 그냥 walk만 주게 될 경우, 현재 스크롤된 만큼의 위치값은 저장되지 않음
});

(부가적) CSS로 시각적 효과 넣어주기

1
2
slider.classList.add('active');
slider.classList.remove('active');

최종 완성 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
const slider = document.querySelector('.items');
let isDown = false;
let startX;
let scrollLeft;

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

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

slider.addEventListener('mousemove', (e) => {
if (!isDown) return;
e.preventDefault();
const moved = e.pageX - slider.offsetLeft;
const walk = (moved - startX) * 2;
slider.scrollLeft = scrollLeft - walk;
});

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

Author

Hoonjoo

Posted on

2022-01-05

Updated on

2022-02-07

Licensed under

Comments