Załóżmy, że chcemy, aby aplikacja internetowa wyglądała jak natywna aplikacja z "Dodaj do ekranu głównego". Jednym z pierwszych kroków jest wyłączenie domyślnego przewijania. Łatwo, prawda?Przewijanie strony w iOS: przewijanie z przepełnieniem: dotknij
// window or document
window.addEventListener("touchmove", function(event) {
// no more scrolling
event.preventDefault();
}, false);
To wszystko cacy, aż dodasz overflow-scrolling
do mieszanki. Mówiąc dokładniej, na iOS byłby to -webkit-overflow-scrolling: touch
.
/* #scrollable happens to be a ul */
#scrollable {
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
Dzięki dodaniu funkcji zapobiegania zdarzeniom, przyspieszane sprzętowo przewijanie w kontenerze nie działa, wyraźnie nie jest to zamierzony efekt.
Oczywistym rozwiązaniem wygląda mniej więcej tak:
// you could do this for multiple elements, of course
var scrollable = document.querySelector("#scrollable");
scrollable.addEventListener("touchmove", function(event) {
// no more bubbling :)
event.stopPropagation();
}, false);
To rozwiązanie wprowadza problemu, jeśli jednak spróbować przewiń w lewo lub w prawo w #scrollable
, to powraca do słuchacza domyślnego przewijania. Oczywiście, należy monitorować zdarzenia, aby sprawdzić, czy zdarzenie touchmove
śledzi w lewo lub w prawo, prawda? Niestety, nie, ponieważ również w okolicznościach, których nie rozumiem, powróć do domyślnego odbiornika przewijania, przewijając pionowo w kontenerze.
Co teraz? Co gorsza, chcemy być idealnie w stanie obsłużyć click
lub kliknij podobnego wydarzenia na poszczególnych li
s (czytaj: touchstart
):
var items = scrollable.querySelectorAll("#scrollable li");
for (var item = 0; item < items.length; item++) {
items[item].addEventListener("touchstart", function() {
// handle the touch start
}, false);
}
Aby rozwiązać ten problem, możemy zwrócić się po prostu za pomocą click
zdarzenia, ale domyślnie celem jest sprawienie, by webapp "czuł się" natywny ze względu na opóźnienie między dotknięciem a odpowiedzią. Aby rozwiązać ten problem, dodamy detektor zdarzeń dla touchstart
i touchend
:
var items = scrollable.querySelectorAll("#scrollable li");
var activeItem = null, startTouch = null;
for (var item = 0; item < items.length; item++) {
items[item].addEventListener("touchstart", function(event) {
startTouch = event.touches[0];
activeItem = this;
}, false);
items[item].addEventListener("touchend", function(event) {
var touch = event.changedTouches[0];
var deltaX = touch.pageX - startTouch.pageX
var deltaY = touch.pageY - startTouch.pageY;
// require the touchstart to be within 10 pixels of the touchend
if (deltaX * deltaX + deltaY * deltaY <= 100)
// handle "click" event
}, false);
}
To wszystko dobrze i dobre, ale wciąż nie rozwiązany problem z domyślna strona przewijanie przejęcie kontroli niektórych touchmove
wydarzeń. Jakieś pomysły?