Post

Slick Slider 드래그 중일 때 클릭 방지

버그 수정 전

Slick Slider로 작업 중, 슬라이드에 클릭 이벤트를 넣으면 드래그했을 때 클릭 이벤트도 같이 실행되는 버그(?)를 발견했습니다. 아무래도 클릭 이벤트는 드래그와 별개로 실행되는게 일반적으로 기대하는 바일텐데, 찾아보니 이미 2015년부터 깃허브 이슈탭에서 꾸준히 제기되었던 오류였습니다. 오류는 생각보다 간단하게 해결됐지만, 혹시나 해결 방법을 발견하지 못한 사람들을 위해 내가 썼던 방법을 소개하려 합니다.

가장 문제되는 부분이 클릭 이벤트이기 때문에 클릭 이벤트라 지칭했지만, mouseovermouseup같은 다른 이벤트 핸들러도 같이 실행됩니다.

 

방법 1 - 이벤트 핸들러를 다른 방식으로 대체

가장 간단한 방법은 이벤트 핸들러를 다른 방식으로 대체하는 것입니다. 예를 들어 슬라이드에 마우스를 올렸을 때 색상이 변경되는 이벤트를 구현하려고 한다면, jQuery의 hover() 이벤트를 사용할 수도 있고, addEventListener()를 사용할 수도 있고, css의 :hover 이벤트를 사용할 수도 있을 것입니다. 이런 식으로 이벤트 리스너를 대체할만한 다른 방식이 있으면 해당 방식으로 대체하는 게 가장 간단한 방법입니다.

onclick으로 링크 이동을 구현하려고 한다면, 아래와 같이 <a> 태그로 링크 이동 방식을 변경하면 정상적으로 작동합니다.

1
2
3
4
5
6
7
8
9
10
11
<!-- X -->
<div id="slider">
	<div onclick="location.href='https://naver.com'">네이버 링크</div>
	<div onclick="location.href='https://samsung.com'">삼성 링크</div>
</div>

<!-- O -->
<div id="slider">
	<a href="https://naver.com" class="slide">네이버 링크</a>
	<a href="https://samsung.com" class="slide">삼성 링크</a>
</div>

 

방법 2 - pointer-events를 사용

pointer-events는 그래픽 요소의 마우스/터치 관련 이벤트(click, mouseup 등)를 제어할 때 사용하는 CSS 속성이다. 이벤트를 제어하는 속성이기 때문에, 이벤트 핸들러보다 우선순위로 적용됩니다.

pointer-events의 속성값

1
2
3
4
5
6
7
8
9
10
11
/* Keyword values */
pointer-events: auto;
pointer-events: none;
pointer-events: visiblePainted; /* SVG only */
pointer-events: visibleFill; /* SVG only */
pointer-events: visibleStroke; /* SVG only */
pointer-events: visible; /* SVG only */
pointer-events: painted; /* SVG only */
pointer-events: fill; /* SVG only */
pointer-events: stroke; /* SVG only */
pointer-events: all; /* SVG only */

지원하는 브라우저

pointer-events에는 총 10가지 속성값이 있지만, 2개를 제외한 나머지 속성값은 모두 SVG에서 사용하도록 설계되어 있습니다. 여기서 사용할 건 HTML 요소에 사용 가능한 2개의 속성값, autonone입니다.

적용 방법

이 방법의 핵심은 드래그했을 때 슬라이드에 pointer-events: none을 부여하는 것입니다. 그럼 드래그하는 건 어떻게 파악할까요? 마우스 이벤트 핸들러인 mouseupmousedown을 사용해 파악할 수 있습니다.

 

마우스 클릭 이벤트 순서

마우스 클릭 이벤트는 mousedown => mouseup => click 순서로 실행됩니다. 이걸 기반으로 mousedown 이벤트가 발생할 때 mousemove(마우스가 움직이면 발생하는 이벤트)가 발생하면 드래그를 했다고 판단해 pointer-events: none을, 그 후 mouseup 이벤트가 발생하면 pointer-events: auto를 반환하는 함수를 구현할 겁니다.

먼저 pointer-events값을 저장할 css 클래스를 지정합니다.

1
2
3
.is-dragging {
	pointer-events: none;
}

그 다음, 드래그 시 is-dragging 클래스를 추가할 함수를 만듭니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
function blockWhileDragging(isDragging) {
	let slides = document.getElementsByClassName("slick-slide");
    
	if (isDragging) {
    	for (let i = 0; i < slides.length; i++) {
        	slides[i].classList.add("is-dragging"); // is-dragging 클래스 추가
 		}
	} else {
    	for (let i = 0; i < slides.length; i++) {
        	slides[i].classList.remove("is-dragging"); // is-dragging 클래스 제거
    	}
	}
}

마지막으로, mouseup, mousemove, mousedown 이벤트 핸들러에 각각 발생할 이벤트를 추가해 줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// mousedown 여부를 판단할 변수
let isMouseDown = false;

// mousedown 이벤트에서 isMouseDown을 true로 변환
document.addEventListener("mousedown", () => {
	isMouseDown = true;
});

// mousemove 이벤트에서 isMouseDown을 판단해 blockWhileDragging 함수 실행
document.addEventListener("mousemove", () => {
	if (isMouseDown) {
    	blockWhileDragging(true);
    } else {
    	blockWhileDragging(false);
    }
});

// mouseup 이벤트에서 mousedown 이전 상태로 초기화
document.addEventListener("mouseup", () => {
	isMouseDown = false;
    blockWhileDragging(false);
});

 

이런식으로 작성을 완료하고 결과물을 확인해보면, 클릭했을 때만 onclick 이벤트가 발생하는 걸 확인할 수 있습니다.

버그 수정 후

이외에도, Slick Slider의 깃허브 이슈탭에는 이 방법 이외에 다양한 방법이 제시되어 있습니다. 이미 많은 사람들이 발견하고, 해결한 버그이기 때문에, 위와 같은 방식으로 오류가 해결이 안된다면, 다른 사람들이 시도한 방식을 찾아보고 적용해보는 것도 좋은 방법일 것 같습니다.

This post is licensed under CC BY 4.0 by the author.