[javascript] 모바일 Safari에서 클릭 이벤트에 대한 300ms 지연 제거

모바일 Safari는 링크 / 버튼을 클릭 할 때부터 이벤트가 시작될 때까지 클릭 이벤트에 300ms 지연이 있다는 것을 읽었습니다 . 지연의 이유는 사용자가 더블 클릭을 하려는지 확인하기 위해 기다리는 것이지만 UX 관점에서 300ms를 기다리는 것은 종종 바람직하지 않습니다.

이 300ms 지연을 제거하는 한 가지 해결책 은 jQuery Mobile “탭”처리를 사용하는 것입니다. 불행히도 저는이 프레임 워크에 익숙하지 않으며 touchend올바른 방식으로 적용 되는 코드 한두 줄만 필요한 경우 큰 프레임 워크를로드하고 싶지 않습니다 .

많은 사이트와 마찬가지로 내 사이트에는 다음과 같은 많은 클릭 이벤트가 있습니다.

$("button.submitBtn").on('click', function (e) {
  $.ajaxSubmit({... //ajax form submisssion
});

$("a.ajax").on('click', function (e) {
  $.ajax({... //ajax page loading
});

$("button.modal").on('click', function (e) {
      //show/hide modal dialog
});

제가하고 싶은 것은 다음과 같은 단일 코드 스 니펫을 사용하여 모든 클릭 이벤트 에서 300ms 지연을 제거하는 것입니다 .

$("a, button").on('tap', function (e) {
 $(this).trigger('click');
 e.preventDefault();
});

그게 나쁜 / 좋은 생각인가요?



답변

이제 일부 모바일 브라우저는 뷰포트를 설정하면 300ms의 클릭 지연을 제거합니다. 더 이상 해결 방법을 사용할 필요가 없습니다.

<meta name="viewport" content="width=device-width, user-scalable=no">

현재 지원되는 Android 용 Chrome입니다 . 안드로이드 파이어 폭스iOS 용 사파리

그러나 iOS Safari에서는 에서 두 번 탭은 확대 / 축소 할 수없는 페이지에서 스크롤 제스처입니다. 이러한 이유로 그들은 300ms 지연을 제거 할 수 없습니다 . 확대 / 축소 할 수없는 페이지에서 지연을 제거 할 수없는 경우 확대 / 축소 가능한 페이지에서 제거 할 가능성이 낮습니다.

Windows Phone 은 또한 확대 할 수없는 페이지에서 300ms 지연을 유지하지만 iOS와 같은 대체 제스처가 없으므로 Chrome 에서처럼 이러한 지연을 제거 할 수 있습니다.다음을 사용하여 Windows Phone에서 지연을 제거 할 수 있습니다.

html {
-ms-touch-action: manipulation;
touch-action: manipulation;
}

출처 : http://updates.html5rocks.com/2013/12/300ms-tap-delay-gone-away

업데이트 2015 년 12 월

지금까지 iOS의 WebKit과 Safari는 사람들이 두 번 탭하여 페이지를 확대 할 수 있도록 한 번의 탭으로 링크 나 버튼을 활성화하기까지 350ms의 지연이있었습니다. Chrome은 이미 몇 달 전에이를 감지하기 위해 더 스마트 한 알고리즘을 사용하여이를 변경했으며 WebKit은 유사한 접근 방식을 따를 것 입니다. 이 기사는 브라우저가 터치 제스처와 함께 작동하는 방식과 브라우저가 오늘날보다 훨씬 더 똑똑해질 수있는 방법에 대한 훌륭한 통찰력을 제공합니다.

2016 년 3 월 업데이트

iOS 용 Safari에서는 두 번째 탭을 감지하는 350ms의 대기 시간이 “빠른 탭”응답을 생성하기 위해 제거되었습니다. width = device-width 또는 user-scalable = no로 뷰포트를 선언하는 페이지에 대해 활성화됩니다. 작성자는 여기에touch-action: manipulation 설명 된대로 CSS 를 사용하여 특정 요소에 대한 빠른 탭 동작을 선택할 수도 있습니다 ( ‘Styling Fast-Tap Behavior’제목으로 스크롤) 및 here .


답변

Financial Times에서 개발 한이 플러그인 -FastClick 은 완벽하게 작동합니다!

추가해야합니다. event.stopPropagation();event.preventDefault();클릭 기능 하거나 바로 뒤에 합니다. 그렇지 않으면 나처럼 두 번 실행될 수 있습니다.

$("#buttonId").on('click',function(event){
    event.stopPropagation(); event.preventDefault();
   //do your magic

});


답변

나는 이것이 오래되었다는 것을 알고 있지만 브라우저에서 “터치”가 지원되는지 테스트 할 수는 없습니까? 그런 다음 “touchend”또는 “click”변수를 만들고 해당 변수를 요소에 바인딩되는 이벤트로 사용 하시겠습니까?

var clickOrTouch = (('ontouchend' in window)) ? 'touchend' : 'click';
$('#element').on(clickOrTouch, function() {
    // do something
});

따라서 코드 샘플은 브라우저에서 “touchend”이벤트가 지원되는지 확인하고 그렇지 않은 경우 “click”이벤트를 사용합니다.

(편집 : “touchend”를 “ontouchend”로 변경)


답변

저는 Hammer.js (Github 페이지) 라는 매우 인기있는 대안을 발견 했는데 이것이 최선의 접근 방식이라고 생각합니다.

Hammer.js는 Fastclick.js (가장 찬성 응답)보다 더 완전한 기능을 갖춘 터치 라이브러리 (많은 스 와이프 명령이 있음)입니다.

하지만주의하세요 : 모바일 장치에서 빠르게 스크롤하면 Hammer.js 또는 Fastclick.js를 사용할 때 UI가 실제로 잠기는 경향이 있습니다. 사이트에 뉴스 피드 또는 사용자가 많이 스크롤하는 인터페이스 (대부분의 웹 앱처럼 보임)가있는 경우 이는 주요 문제입니다. 이러한 이유로 저는 현재 이러한 플러그인을 사용하지 않습니다.


답변

어쨌든 확대 / 축소를 비활성화하면이 작은 지연이 비활성화되는 것 같습니다. 이제 더 이상 두 번 탭할 필요가 없으므로 이해가됩니다.

모바일 웹 페이지에서 확대 / 축소를 “비활성화”하려면 어떻게합니까?

그러나 이것이 가져올 사용성 영향에 유의하십시오. 앱으로 설계된 웹 페이지에는 유용 ​​할 수 있지만보다 일반적인 용도의 ‘정적’페이지 IMHO에는 사용해서는 안됩니다. 낮은 대기 시간이 필요한 애완 동물 프로젝트에 사용합니다.


답변

안타깝게도 이렇게하는 쉬운 방법은 없습니다. 그러니 그냥 사용 touchstart또는 touchend예를 들어 버튼을 클릭 할 때 스크롤 사람이 시작 같은 다른 문제에 당신을 떠날 것입니다. 우리 는 한동안 zepto 를 사용하는데 ,이 정말 좋은 프레임 워크에서도 시간이 지남에 따라 몇 가지 문제가 발생했습니다. 많은 사람들이 닫혀 있지만 간단한 해결책의 분야가 아닌 것 같습니다.

링크에 대한 클릭을 전 세계적으로 처리하는이 솔루션이 있습니다.

   $(document.body).
    on('tap', 'a',function (e) {
      var href = this.getAttribute('href');
      if (e.defaultPrevented || !href) { return; }
      e.preventDefault();
      location.href= href;
    }).
    on('click', 'a', function (e) {
      e.preventDefault();
    });


답변

jquery없이 fastclick 라이브러리없이 쉬운 방법을 찾았습니다. 이것은 나를 위해 작동합니다.

var keyboard = document.getElementById("keyboard");
var buttons = keyboard.children;
var isTouch = ("ontouchstart" in window);
for (var i=0;i<buttons.length;i++) {
    if ( isTouch ) {
        buttons[i].addEventListener('touchstart', clickHandler, false);
    } else {
        buttons[i].addEventListener('click', clickHandler, false);
    }
}