πŸ–± 동일 μš”μ†Œμ˜ 클릭이벀트, 마우슀이벀트 이슈

문제 λ°œμƒ

졜근 μ–΄λ–€ ν”„λ‘œμ νŠΈλ₯Ό μ§„ν–‰ν•˜λ©΄μ„œ ν•œκ°€μ§€ λ°œμƒν–ˆλ˜ μ΄μŠˆμ™€ ν•΄κ²°κ³Όμ •, 해결방법에 λŒ€ν•œ 확신을 닀룬 포슀트 이닀.

쒌우 슀크둀과 같은 μ˜μ—­μ„ κ΅¬ν˜„ν•  λ•Œ, μ›Œλ‚™ 잘 μ•Œλ €μ Έμžˆκ³  높은 μ‚¬μš©μ„ μžλž‘ν•˜λŠ” swiperλͺ¨λ“ˆ λŒ€μ‹  쒌우 μŠ€ν¬λ‘€μ„ 톡해 κ΅¬ν˜„ν•΄λ³΄κ³ μž ν•˜μ˜€λ‹€.

κ΅¬ν˜„κ³Όμ • μžμ²΄μ—λŠ” 큰 λ¬Έμ œκ°€ μ—†μ—ˆλŠ”λ° ν•œκ°€μ§€ λ¬Έμ œκ°€ λ°œμƒν•˜μ˜€λ‹€.

click 이벀트의 경우, λ™μΌν•œ μš”μ†Œ 내에 mousedown - mouseup이 λ°œμƒν•˜λ©΄ click이 ν˜ΈμΆœλ˜λŠ”κ²ƒ κ°™μ•˜λ‹€.

κ·Έ μˆœμ„œλ˜ν•œ λ™μΌν•˜κ²Œ mousedown - mouseup - click이 ν˜ΈμΆœλ˜μ—ˆλ‹€.

κ·Έλž˜μ„œ 그게 μ™œ?

μœ„μ—μ„œ 잠깐 μ–ΈκΈ‰λ˜μ—ˆλŠ”λ°, μ„œλ‘œ λ‹€λ₯Έ μš”μ†Œμ—μ„œ mousedown, mouseup이 μ΄μ–΄μ§€κ²Œλœλ‹€λ©΄ click이 ν˜ΈμΆœλ˜μ§€ μ•Šμ§€λ§Œ λ™μΌν•œ μš”μ†Œμ—μ„œ μ‹œμž‘, 마무리 λœλ‹€λ©΄ click이 ν˜ΈμΆœλ˜μ–΄ μ›ν•˜μ§€ μ•ŠλŠ” 상황에 ν•΄λ‹Ή μ΄λ²€νŠΈκ°€ λ°œμƒν•˜μ˜€λ‹€.

즉, μ‚¬μš©μžμ˜ μž…μž₯μ—μ„œ λ‹¨μˆœ 쒌우 μŠ€ν¬λ‘€μ„ μ›ν–ˆλ˜ 것이 μ˜ˆμƒν•˜μ§€ λͺ»ν•œ ν΄λ¦­μ΄λ²€νŠΈκ°€ λ°œμƒν•˜μ—¬ μš”μ†Œμ— ν• λ‹Ήλœ route둜 μ΄λ™ν•˜λŠ” λ“±μ˜ μ‚¬μ΄λ“œμ΄νŽ™νŠΈκ°€ λ°œμƒν•˜μ˜€λ‹€.

이벀트 μ „νŒŒ 차단을 ν†΅ν•œ ν•΄κ²°

ν•œκ°€μ§€ 해결방법은 ν΄λ¦­μ΄λ²€νŠΈκ°€ μ•„λ‹Œ mouseup이벀트둜 λŒ€μ²΄ν•˜κ³  λ“œλž˜κ·Έμ€‘μΈ μƒνƒœλ₯Ό κ΅¬λΆ„ν•˜μ—¬ 이벀트 μ „νŒŒλ₯Ό λ§‰λŠ”κ²ƒμ΄μ˜€λ‹€.

μ΄λ²€νŠΈκ°€ μ „λ‹¬λ˜λŠ” μˆœμ„œλ‚˜ 이벀트 μ „νŒŒμžμ²΄λ₯Ό λ§‰μ„μˆ˜ μžˆλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ νŠΉμ§•μ„ 잘 μ‚΄λ¦° 해결방법일 수 μžˆλ‹€.

λ‹€λ§Œ μ•„μ‰¬μš΄μ μ€ mouseupμ΄λΌλŠ” ν–‰μœ„λŠ” 생각보닀 λ§Žμ€ 방법을 κ³΅μœ ν•˜κ²Œλ˜λŠ”λ°,

마우슀 νœ μ„ ν΄λ¦­ν•œλ‹€κ±°λ‚˜, λ‹€λ₯Έ μš”μ†Œμ—μ„œ μ‹œμž‘ν•˜κ³  λ“œλž˜κ·Έν•˜μ—¬ ν•΄λ‹Ήμš”μ†Œμ—μ„œ λ§ˆμš°μŠ€μ—…μ„ ν•  κ²½μš°μ—λ„ λ°œμƒν•  수 μžˆλ‹€λŠ” 점이닀.

κ²°κ΅­, λ™μΌν•˜κ²Œ μ‚¬μš©μžκ°€ μ›ν•˜μ§€ μ•ŠλŠ” μƒν™©μ—μ„œλ„ ν•΄λ‹Ή μ΄λ²€νŠΈκ°€ λ°œμƒν•  수 μžˆλ‹€λŠ”μ μ€ ν•΄κ²°λ˜μ§€ μ•Šμ•˜λ‹€.

μ‹€ν–‰ν•¨μˆ˜μ˜ ν˜ΈμΆœμ‹œκ°„ μ œμ–΄

쑰금 λ‹€λ₯΄κ²Œ 접근을 ν•΄λ³΄μž.

κ²°κ΅­ mousedown - mouseup - clickκ³Ό 같이 동일 μš”μ†Œ λ‚΄μ—μ„œ λ°œμƒν•˜λŠ” 이벀트의 ν˜ΈμΆœμˆœμ„œλŠ” λ°”κΏ€ 수 κ°€ μ—†λ‹€.

즉 mouseup을 톡해 λ“œλž˜κ·Έμ€‘μ΄ μ•„λ‹Œ μƒνƒœλ₯Ό μ΄ˆκΈ°ν™” ν•˜κ²Œ λœλ‹€λ©΄ λ‹Ήμ—°νžˆ 이후에 ν˜ΈμΆœλ˜λŠ” clickμ΄λ²€νŠΈμ—μ„œλŠ” λ“œλž˜κ·Έμ€‘μΈ μƒνƒœλ₯Ό ꡬ뢄할 수 μ—†λ‹€.

μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ μ‹€ν–‰λ˜λŠ” ν™˜κ²½μ€ ν•˜λ‚˜μ˜ μ½œμŠ€νƒμœΌλ‘œ μ²˜λ¦¬λ˜μ–΄ ν•„μš”μ‹œ λΉ„λ™κΈ°λ‘œ μ „λ‹¬ν•˜μ—¬ μ‹€ν–‰λ˜λŠ” μˆœμ„œ, μ‹œκ°„μ„ κ°œλ°œμžκ°€ μ–΄λŠμ •λ„ 컨트둀 ν•  수 μžˆλ‹€.

μ΄λŸ¬ν•œ 점이 정말 맀λ ₯μžˆλ‹€κ³  μƒκ°ν•˜λŠ”λ°, μœ„μ˜ λ¬Έμ œλ„ 이와같이 μ ‘κ·Όν•˜μ—¬ ν•΄κ²°ν•  수 μžˆμ—ˆλ‹€.

setTimeout(() => {
  isDragging = false
})

정말 λ‹¨μˆœν•œ ν•œ 쀄 μ΄μ§€λ§Œ λ§Žμ€κ²ƒμ„ μ˜λ―Έν•˜κ³ μžˆλ‹€.

μ € ν•¨μˆ˜λŠ” mouseupλΌλŠ” μ΄λ²€νŠΈκ°€ 싀행될 λ•Œ μ½œλ°±ν•¨μˆ˜λ‘œ μ „λ‹¬λ˜μ–΄ μ‹€ν–‰λ˜λŠ” μ‹€ν–‰ν•¨μˆ˜μ΄λ‹€.

ν•˜μ§€λ§Œ, setTimout을 톡해 λΉ„λ™κΈ°μ²˜λ¦¬ν•˜μ˜€κΈ° λ•Œλ¬Έμ— λ³„λ„μ˜ μ‹œκ°„μ„ 지정해주지 μ•Šμ•˜λ”λΌλ„ μ¦‰μ‹œμ‹€ν–‰λ˜λŠ”κ²ƒμ΄ μ•„λ‹Œ νƒœμŠ€ν¬νμ— μ €μž₯이 λœλ‹€.

μ‚¬μš©μžμ˜ μ΄λ²€νŠΈλ„ 각각의 이벀트 ν•Έλ“€λŸ¬μ— ν• λ‹Ήλ˜μ–΄μžˆλŠ” μ‹€ν–‰ν•¨μˆ˜λ“€μ΄ λΉ„λ™κΈ°λ‘œ μ²˜λ¦¬λ˜λŠ” νŠΉμ§•μΈλ°, μ € setTimeout을 톡해 μ „λ‹¬λ˜λŠ” λ“œλž˜κ·Έμƒνƒœ μ΄ˆκΈ°ν™” λΌλŠ” μ‹€ν–‰ν•¨μˆ˜λŠ” click이벀트의 μ‹€ν–‰ν•¨μˆ˜λ³΄λ‹€ λ’·μˆœμœ„μΈ μƒνƒœλ‘œ νƒœμŠ€ν¬νμ— μ €μž₯λœλ‹€.

μ„ μž…μ„ μΆœμ˜ νŠΉμ§•μ„ κ°–κ³ μžˆλŠ” 큐의 자료규쑰 νŠΉμ„±μƒ click이벀트의 호좜이 λ¨Όμ € 진행이 λ˜μ§€λ§Œ, 아직 isDragging의 μƒνƒœκ°€ μ΄ˆκΈ°ν™”λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— route이동과 같이 ν• λ‹Ήλœ ν΄λ¦­μ΄λ²€νŠΈκ°€ ν˜ΈμΆœλ˜μ§€ μ•ŠλŠ”λ‹€.

λ‹€λ§Œ, μœ„μ˜ click이벀트의 μ‹€ν–‰ν•¨μˆ˜κ°€ μ’…λ£Œλ˜λ©΄ μ½œμŠ€νƒμ΄ λΉ„μ–΄μžˆμŒμ„ κ°μ§€ν•˜κ³  setTimeout의 isDraggingμƒνƒœλ₯Ό μ΄ˆκΈ°ν™”ν•˜λŠ” μ‹€ν–‰ν•¨μˆ˜κ°€ ν˜ΈμΆœλ˜λŠ” 점이닀.

이λ₯Ό 톡해, λ“œλž˜κ·Έμ€‘μΈ μƒνƒœ μ΄ˆκΈ°ν™”λŠ” mouseup에 ν• λ‹Ήν•˜μ˜€λ”λΌλ„ μ‹€μ œ κ·Έ 둜직 μžμ²΄λŠ” click이벀트 호좜 이후에 μž‘λ™λ˜κΈ° λ•Œλ¬Έμ— click의 μ‹€ν–‰ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œλŠ” isDragging의 true, false 두가지 μƒνƒœλ₯Ό μ•Œ 수 있게 λœλ‹€.

swiper λͺ¨λ“ˆμ—μ„œλŠ” μ–΄λ–»κ²Œ 처리될까

λ‚΄κ°€ ν•΄κ²°ν–ˆλ˜ 방법이 μ ˆλŒ€λ‘œ 정닡이라고 μƒκ°ν•˜μ§€ μ•Šκ³ , ν‹€λ¦° 정닡일 수 도 μžˆλ‹€.

λ”°λΌμ„œ λ‹€λ₯Έ λŒ€μ€‘μ μœΌλ‘œ μ‚¬μš©λ˜κ³ μžˆλŠ” λΉ„μŠ·ν•œ 상황이 μƒκΈΈμˆ˜ μžˆλŠ” μ˜€ν”ˆμ†ŒμŠ€λ₯Ό 톡해 μ–΄λ–€ 방법이 μžˆλŠ”μ§€ ν™•μΈν•΄λ³΄κ³ μž ν–ˆλ‹€.

  • swiper

    ν† μš”μΌ κΈ°μ€€ μ£Όκ°„ λ‹€μš΄νšŸμˆ˜κ°€ 70만회 이상인 μ–΄λ§ˆμ–΄λ§ˆν•œ λͺ¨λ“ˆμ΄λ‹€.

onClick?: (swiper: SwiperClass, event: MouseEvent | TouchEvent | PointerEvent) => void;
onTouchStart?: (swiper: SwiperClass, event: MouseEvent | TouchEvent | PointerEvent) => void;
onTouchMove?: (swiper: SwiperClass, event: MouseEvent | TouchEvent | PointerEvent) => void;
onTouchEnd?: (swiper: SwiperClass, event: MouseEvent | TouchEvent | PointerEvent) => void;

λ¨Όμ € ν•΄λ‹Ή λͺ¨λ“ˆμ˜ Swiperμ—μ„œλŠ” μƒμ„±ν•œ μ»€μŠ€ν…€ μ΄λ²€νŠΈκ°€ mouse, touch, pointer 3가지 일반 μ΄λ²€νŠΈλ“€μ„ ν•Έλ“€λ§ν•΄μ£ΌλŠ”κ²ƒ κ°™λ‹€.

pointerλŠ” mouseλ₯Ό ν¬ν•¨ν•œ 쑰금 더 넓은 κ°œλ…μ˜ 이벀트라고 ν•œλ‹€.

core.jsμ—μ„œ SwiperλΌλŠ” ν΄λž˜μŠ€κ°€ 생성될 λ•Œ κ°–κ³ μžˆλŠ” λͺ‡κ°€μ§€ 속성이 ν•΅μ‹¬μœΌλ‘œ 보인닀.

// Clicks
allowClick: true,

preventClicks: true,
preventClicksPropagation: true,

λ˜ν•œ, μ»€μŠ€ν…€ν•˜κ²Œ μƒμ„±λ˜λŠ” clickμ΄λ²€νŠΈλŠ” μ•„λž˜μ™€ 같은 쀑간단계λ₯Ό 거치게 λ˜λŠ”λ°,

export default function onClick(e) {
  const swiper = this
  if (!swiper.enabled) return
  if (!swiper.allowClick) {
    if (swiper.params.preventClicks) e.preventDefault()
    if (swiper.params.preventClicksPropagation && swiper.animating) {
      e.stopPropagation()
      e.stopImmediatePropagation()
    }
  }
}

swiper.allowClick속성이 false 라면 이벀트 μ „νŒŒμžμ²΄λ₯Ό 막아버린닀.

이 ꡬ뢄 둜직이 맀우 핡심이닀.

Swiperλͺ¨λ“ˆμ—μ„œ μ»€μŠ€ν…€ν•˜κ²Œ μƒμ„±ν•œ onTouchMove이벀트의 λ‚΄λΆ€ μ½”λ“œλ₯Ό 보닀보면 λͺ¨λ“  μ’…λ£Œμƒν™© 전에 값이 ν• λ‹Ήλ˜λŠ”κ²ƒμ΄ μžˆλ‹€.

swiper.allowClick = false

즉, λ“œλž˜κ·Έμ€‘μΈ μƒν™©μ—λŠ” λ‚΄λΆ€μ μœΌλ‘œ 클릭이 κ°€λŠ₯ν•œ μƒνƒœλ₯Ό λΆ€μ •ν™” ν•˜λŠ” ꡬ문이닀.

그리고 onTouchEnd의 μ»€μŠ€ν…€ 이벀트 내뢀에 λˆˆμ—λ„λŠ” ν•œκ°€μ§€ 둜직이 μžˆλ‹€.

nextTick(() => {
  if (!swiper.destroyed) swiper.allowClick = true
})

μ’…λ£Œλ  λ•Œ, swiperλͺ¨λ“ˆμ΄ μ‘΄μž¬ν•œλ‹€λ©΄ swiper.allowClick 속성을 λ‹€μ‹œ 클릭 κ°€λŠ₯ν•œ μƒνƒœλ‘œ 변경을 ν•΄μ£ΌλŠ”λ°,

λ†€λžκ²Œλ„ μ € nextTickλ©”μ†Œλ“œμ˜ 역할은

function nextTick(callback, delay = 0) {
  return setTimeout(callback, delay)
}

λ˜‘κ°™λ‹€.

μ΄ˆκΈ°ν™” λ‘œμ§μ„ λΉ„λ™κΈ°λ‘œ μ „λ‹¬ν•˜μ—¬ click이벀트 이후에 μ‹€ν–‰λ˜λ„λ‘ ν•΄μ£Όμ—ˆλ‹€.

κ²°λ‘ 

μš”μ†Œλ₯Ό μ„ νƒν•œλ‹€λŠ” ν–‰μœ„μ— mouseup이벀트λ₯Ό μ‚¬μš©ν•˜λŠ”κ²ƒμ΄ ꢌμž₯λ˜μ§€ μ•Šκ³ , λ™μΌν•œ μš”μ†Œ 내에 mousedownκ³Ό mouseup이 ν•¨κ»˜ μž‘λ™λ˜μ•Όν•˜λŠ” click이벀트λ₯Ό 적극 ꢌμž₯ν•˜κ³  μžˆμ—ˆκ³  κ·ΈλŸ¬ν•œ μ΄μœ κ°€ μ‚¬μš©μžμ˜ μž…μž₯μ—μ„œ μ˜ˆμƒ μ™Έμ˜ 상황을 λ°œμƒμ‹œν‚¬μˆ˜ μžˆλ‹€λŠ”μ μ΄ μ΄μœ μ˜€κΈ° λ•Œλ¬Έμ— κ·ΈλŸ¬ν•œ 방법을 μœ μ§€ν•œ μ±„λ‘œ 해결에 μ ‘κ·Όν–ˆλ‹€λŠ”κ²ƒμ— 큰 μ˜λ―Έκ°€ μžˆμ—ˆλ˜κ²ƒ κ°™λ‹€.

또, λŒ€μ€‘μ μΈ λͺ¨λ“ˆμ΄ μ„ νƒν–ˆλ˜ 방식과 λ™μΌν•œ λ°©μ‹μ˜ 접근이라 λ‚˜λ¦„μ˜ κ°€μΉ˜μžˆλŠ” 방법인것 κ°™μ•„ λΏŒλ“―ν•˜κΈ°λ„ ν•˜λ‹€.


@SangMin
πŸ‘† H'e'story

πŸš€GitHub