Wyeliminuj 300 ms opóźnienia w przypadku kliknięć w mobilnej przeglądarce Safari


89

Czytałem, że mobilna Safari ma 300 ms opóźnienia w przypadku kliknięć od momentu kliknięcia łącza / przycisku do momentu uruchomienia zdarzenia. Powodem opóźnienia jest oczekiwanie, aby zobaczyć, czy użytkownik zamierza dwukrotnie kliknąć, ale z perspektywy UX czekanie 300 ms jest często niepożądane.

Jednym z rozwiązań pozwalających wyeliminować to 300 ms opóźnienia jest użycie obsługi „dotknięcia” w jQuery Mobile. Niestety nie jestem zaznajomiony z tym frameworkiem i nie chcę ładować jakiegoś dużego frameworka, jeśli potrzebuję tylko jednego lub dwóch wierszy kodu zastosowanych touchendwe właściwy sposób.

Podobnie jak wiele innych witryn, moja witryna ma wiele takich zdarzeń kliknięcia:

$("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
});

Chciałbym pozbyć się 300 ms opóźnienia WSZYSTKICH tych zdarzeń kliknięcia za pomocą pojedynczego fragmentu kodu, takiego jak ten:

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

Czy to zły / dobry pomysł?



@Pointy dzięki, to może po prostu zadziałać ...
tim peterson

„… oczywiście nie jest to wspaniałe z punktu widzenia UX”. Byłbym ostrożny w stosunku do tego założenia.
Oliver Moran

1
@OliverMoran, dzięki za korektę, właśnie zredagowałem to zdanie, zobacz pytanie powyżej ..
tim peterson

Odpowiedzi:


73

Niektóre przeglądarki mobilne eliminują teraz 300 ms opóźnienia kliknięcia, jeśli ustawisz obszar wyświetlania. Nie musisz już używać obejść.

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

Jest to obecnie obsługiwane Chrome na Androida , Firefox na Androida i Safari na iOS

Jednak w iOS Safari dwukrotne dotknięcie to gest przewijania na stronach, których nie można powiększyć. Z tego powodu nie mogą usunąć opóźnienia 300 ms . Jeśli nie mogą usunąć opóźnienia na stronach, których nie można powiększyć, jest mało prawdopodobne, aby usunęli je na stronach, które można powiększać.

Telefony z systemem Windows zachowują również opóźnienie 300 ms na stronach, których nie można powiększyć, ale nie mają alternatywnego gestu, takiego jak iOS, więc mogą usunąć to opóźnienie, tak jak ma to miejsce w Chrome.Możesz usunąć opóźnienie w Windows Phone za pomocą:

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

Źródło: http://updates.html5rocks.com/2013/12/300ms-tap-delay-gone-away

UPDATE 2015 grudzień

Do tej pory WebKit i Safari na iOS miały 350 ms opóźnienia, zanim pojedyncze dotknięcie aktywowało linki lub przyciski, aby umożliwić ludziom powiększanie stron za pomocą podwójnego dotknięcia. Chrome zmienił to już kilka miesięcy temu, używając inteligentniejszego algorytmu do wykrywania tego, a WebKit zastosuje podobne podejście . Artykuł zawiera świetne informacje o tym, jak przeglądarki współpracują z gestami dotykowymi i jak przeglądarki mogą być o wiele inteligentniejsze niż obecnie.

UPDATE 2016 marzec

W Safari na iOS, 350 ms czasu oczekiwania na wykrycie drugiego stuknięcia został usunięty, aby utworzyć odpowiedź „fast-tap”. Jest to włączone dla stron, które deklarują obszar roboczy z wartością width = device-width lub user-scalable = no. Autorzy mogą również zdecydować się na zachowanie szybkiego stuknięcia w określone elementy, używając CSS, touch-action: manipulationjak opisano tutaj (przewiń w dół do nagłówka „Stylowe szybkie dotknięcie ”) i tutaj .


Właściwie są wydarzenia dotykowe dla WP: stackoverflow.com/questions/13396297/ ...
Cedric Reichenbach

1
Tak, co jest kontrolowane przez -ms-touch-action, jak napisałem w moim poście.
NoNameProvided

1
Problem nadal występuje w systemie iOS podczas uruchamiania aplikacji ze strony głównej (wersja autonomiczna). Jeśli ktoś znalazłby dla niego przyzwoite obejście, byłoby to bardzo mile widziane
Miguel Guardo

1
Ustawienie wartości dotyku na manipulację jest najbliższe pożądanej wydajności, ale jak powiedział wcześniej @MiguelGuardo, efekt zostanie utracony po dodaniu strony internetowej do ekranu głównego w iOS jako samodzielnej aplikacji.
T. Steele,

Może być ktoś może włamać UIWebView - stackoverflow.com/questions/55155560/...
Eazy

43

Ta wtyczka -FastClick opracowana przez Financial Times robi to doskonale dla Ciebie!

Upewnij się jednak, że dodajesz event.stopPropagation();i / lub event.preventDefault();bezpośrednio po funkcji kliknięcia, w przeciwnym razie może działać dwa razy tak, jak u mnie, tj .:

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

});

3
To nie jest idealne, jeśli używasz jquery mobile (w każdym razie wersja 1.3.2), przerywa zamykanie widżetu panelu github.com/jquery/jquery-mobile/issues/6440
ryan0

Właśnie dlatego event.stopPropagation () jest właśnie powodem, dla którego trafiłem na tę stronę. Działa idealnie, dziękuję!
Lukas

@Jonathan fastclickrobi swoją magię tylko na urządzeniach dotykowych, które mają problem z opóźnieniem (w innym przypadku jest to automatycznie pomijane ). Jednak samo dodanie stopPropagation& preventDefaultpo każdym zdarzeniu kliknięcia może mieć niepożądany wpływ na wszystkie programy obsługi zdarzeń we wszystkich przeglądarkach.
użytkownik

17

Wiem, że to jest stare, ale czy nie możesz po prostu przetestować, czy przeglądarka obsługuje „dotyk”? Następnie utwórz zmienną, która jest albo „dotknięta”, albo „kliknij” i wykorzystaj tę zmienną jako zdarzenie, które zostanie przypisane do Twojego elementu?

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

Tak więc ten przykładowy kod sprawdza, czy zdarzenie „touchend” jest obsługiwane w przeglądarce, a jeśli nie, to używamy zdarzenia „click”.

(Edycja: zmieniono „touchend” na „ontouchend”)


Dzięki, podoba mi się ta prostota. Chciałbym, żeby inni mówili o jego możliwych pułapkach.
tim Peterson

4
Zdarzenie touchend nie może zastąpić zdarzenia kliknięcia, ponieważ @Andreas Köberle wyjaśnia w swojej odpowiedzi. Na przykład, jeśli przewiniesz i zatrzymasz palec na przycisku, uruchomi to link ...
adriendenat

Jest to niesamowite, lekkie rozwiązanie bez konieczności dołączania dużej, grubej dodatkowej biblioteki rzeczy, aby pozbyć się opóźnienia. Chciałbym móc głosować 5 razy w tej sprawie! (o ile nie martwisz się scenariuszem przewijania!)
tonejac

2
W przypadku komputerów / przeglądarek obsługujących zdarzenia dotyku i kliknięcia jest to złe rozwiązanie.
Alexander O'Mara,

1
Niektóre urządzenia obsługują zarówno zdarzenia dotyku, jak i kliknięcia i chcesz, aby oba były uruchamiane w różnych sytuacjach. Doświadczyliśmy sytuacji, w których niektóre tablety z systemem Windows lub Android, które są wyposażone w mysz, będą oczywiście uruchamiać zdarzenie kliknięcia po kliknięciu rzeczy, ale także wywoływały zdarzenia dotykowe po dotknięciu. Oznaczało to, że trzeba było słuchać obu wydarzeń. Jako dodatkowy czynnik komplikujący, niektóre urządzenia syntetyzowały zdarzenie kliknięcia po dotknięciu, więc słuchanie obu na tych urządzeniach może spowodować dwukrotne uruchomienie modułu obsługi zdarzeń, chyba że jesteś ostrożny.
1800 INFORMACJA

12

Natknąłem się na niezwykle popularną alternatywę o nazwie Hammer.js (strona Github), która moim zdaniem jest najlepszym podejściem.

Hammer.js jest bardziej w pełni funkcjonalną biblioteką dotykową (ma wiele poleceń machnięcia) niż Fastclick.js (najbardziej pozytywna odpowiedź).

Uważaj jednak: szybkie przewijanie na urządzeniach mobilnych ma tendencję do blokowania interfejsu użytkownika, gdy używasz Hammer.js lub Fastclick.js. Jest to poważny problem, jeśli Twoja witryna ma kanał aktualności lub interfejs, w którym użytkownicy będą dużo przewijać (wygląda na to, że większość aplikacji internetowych). Z tego powodu w tej chwili nie używam żadnej z tych wtyczek.


2
Nie używaj Hammerjs. Ma kilka poważnych problemów, na przykład: github.com/EightMedia/hammer.js/issues/388 github.com/EightMedia/hammer.js/issues/366 Przynajmniej nie używaj go, dopóki nie zostaną naprawione
Adonis K. Kakoulidis

2

W jakiś sposób wyłączenie powiększenia wydaje się wyłączać to małe opóźnienie. Ma to sens, ponieważ dwukrotne dotknięcie nie jest już potrzebne.

Jak mogę „wyłączyć” powiększenie mobilnej strony internetowej?

Należy jednak pamiętać o wpływie, jaki będzie to miało na użyteczność. Może być przydatny w przypadku stron internetowych zaprojektowanych jako aplikacje, ale nie powinien być używany w przypadku bardziej ogólnych stron „statycznych” IMHO. Używam go do projektu dla zwierząt domowych, który wymaga małego opóźnienia.


1

Niestety nie ma na to prostego sposobu. Tak więc samo użycie touchstartlub touchendpozostawi Cię z innymi problemami, na przykład gdy ktoś zacznie przewijać po kliknięciu przycisku. Używamy zepto od jakiegoś czasu i nawet z tym naprawdę dobrym frameworkiem są pewne problemy, które pojawiły się z czasem. Wiele z nich jest zamkniętych , ale wydaje się, że nie jest to pole do prostego rozwiązania.

Mamy to rozwiązanie do obsługi kliknięć linków na całym świecie:

   $(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();
    });

- @ Andreas, dziękuję, więc nie opowiadasz się za korzystaniem z ogólnego taprozwiązania, które opublikowałem, i nie uwzględniaj tapwydarzeń według elementu?
tim Peterson

Nie, nie o to chodzi. Nie chodzi o to, aby samodzielnie budować taprozwiązanie. Zaktualizuję moją odpowiedź.
Andreas Köberle

- @ Andreas, dziękuję za odpowiedź, wiele zdarzeń związanych z kliknięciami to AJAX, więc zdarzenie domyślne zostało już zablokowane. Czy mógłbyś zaktualizować swoją odpowiedź, aby to załatwić? Wydawałoby się, że moje ogólne taprozwiązanie wyglądałoby tak samo jak twoje w tym przypadku?
tim Peterson

1

Szukałem łatwego sposobu bez jQuery i bez biblioteki fastclick. To działa dla mnie:

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);          
    }
}

0

Tylko po to, aby podać dodatkowe informacje.

W systemie iOS 10 <button>s na mojej stronie nie mogły być uruchamiane w sposób ciągły. Zawsze było opóźnienie.

Próbowałem fastclick / Hammer / tapjs / zastępując kliknięcie za pomocą Touchstart, wszystko zawiodło.

UPDATE: powodem wydaje się być to, że przycisk jest zbyt blisko krawędzi! przesuń go w pobliże środka i nie ma opóźnienia!


0

Powinieneś jawnie zadeklarować tryb pasywny :

window.addEventListener('touchstart', (e) => {

    alert('fast touch');

}, { passive : true});

0

W jQuery można powiązać zdarzenie „touchend”, które uruchamia kod natychmiast po dotknięciu (działa jak klawisz w klawiaturze). Przetestowano na aktualnych wersjach tabletów Chrome i Firefox. Nie zapomnij także o „kliknięciu” w przypadku laptopów z ekranem dotykowym i urządzeń stacjonarnych.

jQuery('.yourElements').bind('click touchend',function(event){

    event.stopPropagation();
    event.preventDefault();

	// everything else
});

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.