Slick Slider로 작업 중 한 가지 버그를 발견. 슬라이드에 클릭 이벤트를 넣으면, 드래그해서 슬라이드를 스와이프 했을 때 클릭 이벤트도 같이 실행되는 버그다. 아무래도 클릭 이벤트는 드래그와 별개로 실행되는게 일반적으로 기대하는 바일텐데, 찾아보니 이미 2015년부터 깃허브 이슈탭에서 꾸준히 제기되었던 오류였다. 오류는 생각보다 간단하게 해결됐지만, 혹시나 해결 방법을 발견하지 못한 사람들을 위해 내가 썼던 방법을 소개하려 한다.
가장 문제가 되는 부분이 클릭 이벤트이기 때문에 클릭 이벤트라 지칭했지만, mouseover나 mouseup같은 다른 이벤트 핸들러도 같이 실행된다.
방법 1 - 이벤트 핸들러를 다른 방식으로 대체
가장 간단한 방법은 이벤트 핸들러를 다른 방식으로 대체하는 것이다. 예를 들어 슬라이드에 마우스를 올렸을 때 색상이 변경되는 이벤트를 구현하려고 한다면, jQuery의 hover() 이벤트를 사용할 수도 있고, addEventListener()를 사용할 수도 있고, css의 :hover 이벤트를 사용할 수도 있을 것이다. 이런 식으로 이벤트 리스너를 대체할만한 다른 방식이 있으면 해당 방식으로 대체하는 게 가장 간단한 방법이다.
onclick으로 링크 이동을 구현하려고 한다면,
<div id="slider">
<div onclick="location.href='https://naver.com'">네이버 링크</div>
<div onclick="location.href='https://samsung.com'">삼성 링크</div>
</div>
아래와 같이 a 태그로 링크 이동 방식을 변경하면 정상적으로 작동한다.
<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의 속성값
/* 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개의 속성값, auto와 none이다.
pointer-events | 1 | 12 | 4 | 9 | 1.5 |
HTML 적용 | 2 | 12 | 4 | 15 | 3.6 |
적용 방법
이 방법의 핵심은 드래그했을 때 슬라이드에 pointer-events: none을 부여하는 것이다. 그럼 드래그하는 건 어떻게 파악할까? 마우스 이벤트 핸들러인 mouseup과 mousedown을 사용한다.
마우스 클릭 이벤트 순서
마우스 클릭 이벤트는 mousedown => mouseup => click 순서로 이벤트가 실행된다. 이걸 기반으로 mousedown 이벤트가 발생할 때 mousemove(마우스가 움직이면 발생하는 이벤트)가 발생하면 드래그를 했다고 판단해 pointer-events: none을, 그 후 mouseup 이벤트가 발생하면 pointer-events: auto를 반환하는 함수를 구현할 것이다.
먼저 pointer-events값을 저장할 css 클래스를 지정한다.
.is-dragging {
pointer-events: none;
}
그 다음, 드래그 시 is-dragging 클래스를 추가할 함수를 만든다.
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 이벤트 핸들러에 각각 발생할 이벤트를 추가한다.
// 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의 깃허브 이슈탭에는 이 방법 이외에 다양한 방법이 제시되어있다. 이미 많은 사람들이 발견하고, 해결한 버그이기 때문에, 위와 같은 방식으로 오류가 해결이 안된다면, 다른 사람들이 시도한 방식을 찾아보고 적용해보는 것도 좋은 방법일 것 같다.
'Language > JavaScript' 카테고리의 다른 글
[JS] 파일 형식의 input에 업로드한 이미지 미리보기 (0) | 2023.10.08 |
---|---|
[JS] Input keydown 이벤트가 두번 실행될 때 (0) | 2023.10.04 |
[JS] 텍스트의 줄 바꿈을 그대로 표현하고 싶은 경우 - <pre> 태그 (0) | 2023.03.28 |
[JS] 이메일 유효성 검사 (0) | 2023.03.15 |
[JS] 전화번호 유효성 검사 (0) | 2023.03.15 |