본문으로 건너뛰기

모바일 페이지 클릭 관통 문제 해결 방안

무료2015-08-24#JS#Front-End#Solution#click through#zepto点击穿透#点透#点穿#300ms延迟#解决点透问题#跨页面点击穿透#ghost click

모바일 페이지의 클릭 관통 문제는 매우 쉽게 마주치는 초급 문제로, 본고는 그 원리 및 각종 해결 방안을 상세히 설명한다

##一.click 과 300ms 지연

모바일 브라우저는 특수한 기능을 제공합니다: 더블탭 (double tap) 확대

300ms 의 지연은 여기서 비롯되며, 사용자가 페이지를 터치한 후, 더블탭 (double tap) 동작인지 판단하기 위해 잠시 기다려야 하며, 즉시 싱글클릭 (click) 에 응답하는 것이 아닙니다. 기다리는 시간은 약 300ms 입니다. 이전에 간단한 소개가 있었습니다: [黯羽輕揚:HTML5 터치 이벤트](/articles/html5 터치 이벤트/)

모바일 이벤트는 touchstarttouchmovetouchend 를 제공하지만 tap 지원은 제공하지 않습니다. 주류 프레임워크 (라이브러리) 는 모두 수동으로 커스텀 tap 이벤트를 구현하여 300ms 지연을消除하고 페이지 응답 속도를 향상시키려 합니다. 간단한 페이지의 경우 touchstart 또는 touchend 를 tap 으로 사용할 수 있지만, 몇 가지 문제가 있습니다. 예를 들어, 손가락이 목표 요소에 접촉한 후 누른 채 천천히 응답 영역에서 벗어나면 touchstart 이벤트가 트리거되어 대응하는 이벤트 핸들러가 실행됩니다 (본래 트리거되어서는 안 됩니다). touchend 이벤트에도 유사한 문제가 있습니다.

또한, 네이티브 touch 이벤트를 사용해도 클릭 관통 문제가 존재합니다. click 은 touch 시리즈 이벤트 발생 후 약 300ms 가 지나야 트리ガー되므로, touch 와 click 을 혼용하면 확실히 점透 문제를 일으킵니다. 아래에서 상세히 설명합니다

##二.클릭 관통 문제

클릭 관통 현상에는 3 종류가 있습니다:

  • 클릭 관통 문제: 마스크층 (mask) 위의 닫기 버튼을 클릭하면, 마스크층이 사라진 후 버튼 아래 요소의 click 이벤트가 트리거된 것을 발견

마스크층의 닫기 버튼에绑定된 것은 touch 이벤트이고, 버튼 아래 요소에绑定된 것은 click 이벤트입니다. touch 이벤트가 트리거된 후 마스크층이 사라지고, 300ms 후에 이 점의 click 이벤트가 fire 되며, event 의 target 은 당연히 버튼 아래 요소가 됩니다. 버튼이 마스크층과 함께 사라졌기 때문입니다

  • 크로스페이지 클릭 관통 문제: 버튼 아래가 마침 href 속성이 있는 a 태그라면, 페이지가 점프합니다

a 태그 점프는 기본적으로 click 이벤트가 트리ガー되므로, 원리는 위와 완전히 동일합니다

  • 또 다른 크로스페이지 클릭 관통 문제: 이번에는 mask 가 없고, 직접 페이지 내 버튼을 클릭하여 새 페이지로 점프한 후, 새 페이지 중 대응 위치 요소의 click 이벤트가 트리거된 것을 발견

마스크층의 이치와 같아서, js 제어 페이지 점프 로직이 touch 이벤트에绑定되어 있고, 게다가 새 페이지 중 대응 위치의 요소가 click 이벤트에绑定되어 있고, 게다가 페이지가 300ms 이내에 점프를 완료하면, 세 조건이 동시에 만족될 때 이 상황이 발생합니다

굳이 세분하면 네 번째도 있지만, 확률은 매우 낮습니다. 새 페이지 중 대응 위치 요소가 마침 a 태그이고, 이후 연속 점프가 발생합니다……이러한 것들은 모두 클릭 관통 문제입니다

##三.해결 방안

문제는已经很明了하며, 많은 해결 방안이 있지만,思路는不外乎 2 종류입니다:

  1. touch 와 click 을 혼용하지 않기

touch 후 300ms 에 click 이 트리ガー되는既然, touch 만 사용하거나 click 만 사용하면 자연스럽게 문제는 존재하지 않습니다

  1. touch 후의 click 을 먹기 (또는 소비하기)

여전히 tap 을 사용하지만, 클릭 관통이 발생할 가능성이 있는 상황에서 추가 처리를 수행합니다. 무엇으로 가리거나, 또는 tap 후 350 밀리초 지연하여 mask 를 숨기거나, pointer-events, 아래 요소의 이벤트 핸들러 내에서 검출 수행 (글로벌 flag 와 연계) 등, 먹을 수 있으면 됩니다

상세한 해결 방안:

  1. touch 만 사용

가장 간단한 해결 방안으로, 클릭 관통 문제를 완벽하게 해결

페이지 내의 모든 click 을 touch 이벤트 (touchstart、'touchend'、'tap') 로 교체합니다. 특히 주의가 필요한 것은 a 태그로, a 태그의 href 도 click 이므로, 제거하고 js 제어 점프로 교체하거나, 직접 span + tap 제어 점프로 변경합니다. 요구가 높지 않다면, 미끄러지거나 미끄러져 들어와서 이벤트가 트리거되는 것을気に하지 않는다면, span + touchend 로 충분합니다. tap 은 서드파티 라이브러리를 도입해야 하기 때문입니다

a 태그를 사용하지 않아도 문제 없습니다. 모바일 app 개발에서는 SEO 를 고려할 필요가 없으며, a 태그를 사용해도 일반적으로 모든 기본 스타일을 제거하므로, 차라리 직접 span 을 사용하는 것이 낫습니다

  1. click 만 사용

下下策입니다. 300ms 지연을 가져오므로, 페이지 내의 모든 커스텀 인터랙션에 300 밀리초의 지연이 추가됩니다. 생각하기만 해도 느립니다

touch 를 사용하지 않으면 touch 후 300ms 에 click 이 트리거되는 문제는 존재하지 않습니다. 인터랙션성 요구가 높지 않다면 이렇게 할 수 있지만, 강력 비추천입니다. 빠른 것이 항상 좋습니다

  1. 무엇으로 가리기

비교적 어리석은 방법으로, 절대 사용하지 마십시오

葉小釵의「국화」대법. 자세한 정보는 【모바일 단 호환 문제 연구】javascript 이벤트 메커니즘 상세 해설 (모바일 호환을涉及) 참조

  1. tap 후 350ms 지연하여 mask 숨기기

개조가 최소로, 단점은 mask 를 숨기는 것이 느려진다는 것입니다. 350ms 는여전히 느리다고 느껴집니다

mask 에 대해서만 처리하면 되며, 개조가 매우 작습니다. 요구가 높지 않다면, 이를 사용하는 것이省力입니다

  1. pointer-events

비교적麻烦하고 결함이 있어, 사용을 권장하지 않습니다

mask 은폐 후, 버튼 아래 요소에 pointer-events: none; 스타일을 추가하여 click 이 통과하게 하고, 350ms 후에 이 스타일을 제거하여 응답을 회복합니다

단점은 mask 사라진 후의 350ms 내, 사용자는 버튼 아래 요소를 클릭해도 반응하지 않는 것을 볼 수 있습니다. 사용자의 손속도가 매우 빠르다면 반드시 발견합니다

  1. 아래 요소의 이벤트 핸들러 내에서 검출 수행 (글로벌 flag 와 연계)

비교적麻烦하며, 사용을 권장하지 않습니다

글로벌 flag 로 버튼 클릭의 위치 (좌표점) 를 기록하고, 아래 요소의 이벤트 핸들러 내에서 event 의 좌표점을 판단하여, 같으면 저런 미운 click 이므로 응답을 거부합니다

위는 단지想法로, 테스트하지 않았습니다.实在안되면 타임스탬프를 기록하여 판단하고, 350ms 대기합니다. 이렇게 하면 pointer-events 와 거의 같아집니다

  1. fastclick

사용하기 쉬운 해결 방안으로, 몇 KB 더 로드하는 것을気に하지 않는다면, 사용을 권장하지 않습니다. 버그를 마주친 사람이 있기 때문입니다. 자세한 정보는 Fastclick 导致 click 이벤트가 2 회 트리거되는 문제 참조

먼저 fastclick 라이브러리를 도입한 후, 페이지 내의 모든 touch 이벤트를 click 으로 교체합니다. 실제로는 조금麻烦합니다. 이 몇 KB 를 도입하여 점透 문제를 해결하는 것은 가치가 없다고建議합니다. 차라리 첫 번째 방법을 사용하는 것이 낫습니다

##四.DEMO

많은 테스트 페이지를 작성했습니다. 참조하세요: Git @OSC ayqy / my.js

###참고 자료

  • 선배 박문若干

댓글

아직 댓글이 없습니다

댓글 작성