evento de rolagem javascript para iPhone / iPad?

107

Não consigo capturar o evento de rolagem em um iPad. Nada disso funciona, o que estou fazendo de errado?

window.onscroll=myFunction;

document.onscroll=myFunction;

window.attachEvent("scroll",myFunction,false);

document.attachEvent("scroll",myFunction,false);

Todos eles funcionam até mesmo no Safari 3 no Windows. Ironicamente, TODOS os navegadores no PC são compatíveis, window.onload=caso você não se importe em destruir os eventos existentes. Mas não vá no iPad.

ck_
fonte

Respostas:

146

O iPhoneOS captura onscrolleventos, exceto da maneira que você espera.

O movimento panorâmico de um dedo não gera nenhum evento até que o usuário pare - um onscrollevento é gerado quando a página para de se mover e é redesenhada - conforme mostrado na Figura 6-1.

Da mesma forma, a rolagem com 2 dedos dispara onscrollsomente depois que você parar de rolar.

A maneira usual de instalar o manipulador funciona, por exemplo

window.addEventListener('scroll', function() { alert("Scrolled"); });
// or
$(window).scroll(function() { alert("Scrolled"); });
// or
window.onscroll = function() { alert("Scrolled"); };
// etc 

(Consulte também https://developer.apple.com/library/content/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html )

Kennytm
fonte
23
Obrigado, isso me forçou a olhar mais para o problema. A verdadeira resposta foi detectar que a parte superior da janela de visualização no iphone / ipad só funciona com, window.pageYOffset e não document.body.scrollTop||document.documentElement.scrollTop como qualquer outro navegador / hardware existente.
ck_
6
@ck_ Infelizmente no IPAD window.pageYOffsetnão é atualizado na fase de desaceleração, mas apenas quando a rolagem termina.
Adaptabi
2
É uma má prática substituir diretamente window.onscroll. Adicionar um ouvinte de evento seria melhor. Use window.addEventListener ('scroll', function () {alert ('scrolled!');});
Kevin Dice
4
ehm .. na verdade, window.onscroll está disparando no meu ipad o tempo todo, enquanto faz panorâmicas, e depois de panorâmicas, enquanto desacelera. algo mudou?
commonpike
Safari (e talvez outros) mudou para usar WKWebView com iOS 8. Chrome e Cordova ainda usam UIWebView, então eles ainda exibem o problema com eventos de rolagem contínua não sendo emitidos. No entanto, existe um plug-in WKWebView para Cordova.
jiku de
105

Para iOS, você precisa usar o evento touchmove , bem como o evento scroll como este:

document.addEventListener("touchmove", ScrollStart, false);
document.addEventListener("scroll", Scroll, false);

function ScrollStart() {
    //start of scroll event for iOS
}

function Scroll() {
    //end of scroll event for iOS
    //and
    //start/end of scroll event for other browsers
}
George Filippakos
fonte
37
Este evento só é disparado quando o usuário está rolando ativamente, ele não é disparado durante a fase de desaceleração da rolagem momentum.
Jon Tirsen
mudei o código para incluir o código de detecção de rolagem final para iOS
George Filippakos
Você também pode querer adicionar um ouvinte para "touchend", que agirá de forma semelhante à rolagem na área de trabalho.
BingeBoy
1
Observe que isso não fornece acesso durante a fase de rolagem
Ben Sewards,
3
já se passaram três anos. Não consigo obter uma atualização em tempo real da posição de rolagem durante a desaceleração. como devo escrever meu aplicativo de mapas ?????
FlavorScape
38

Desculpe por adicionar outra resposta a uma postagem antiga, mas normalmente recebo um evento de rolagem muito bem usando este código (funciona pelo menos no 6.1)

element.addEventListener('scroll', function() {
    console.log(this.scrollTop);
});

// This is the magic, this gives me "live" scroll events
element.addEventListener('gesturechange', function() {});

E isso funciona para mim. A única coisa que ele não faz é fornecer um evento de rolagem para a desaceleração da rolagem (assim que a desaceleração for concluída, você obtém um evento de rolagem final, faça o que quiser com ele.) Mas se você desabilitar a inércia com css ao fazer isso

-webkit-overflow-scrolling: none;

Você não fica com inércia em seus elementos, para o corpo, embora você possa ter que fazer o clássico

document.addEventListener('touchmove', function(e) {e.preventDefault();}, true);
Dave Mackintosh
fonte
7
Por que votar negativamente em uma resposta válida e não deixar um comentário explicando o problema com ela?
Dave Mackintosh
3
porque downvoting é fácil e rápido. : /
Zeshan Ahmed
5
Uma resposta é SEMPRE "válida" de acordo com seu autor ... Ninguém posta uma resposta sabidamente inválida. Mas sim, eles deveriam ter explicado por que votaram negativamente.
Matthieu Charbonnier
3
gesturechangeevents não é padrão e é compatível apenas com Safari: developer.mozilla.org/en-US/docs/Web/Events/gesturechange
Nicolas Bouvrette
6

Consegui obter uma ótima solução para esse problema com iScroll, com a sensação de rolagem dinâmica e tudo mais https://github.com/cubiq/iscroll O documento do github é ótimo, e eu o segui na maior parte. Aqui estão os detalhes da minha implementação.

HTML: envolvi a área rolável do meu conteúdo em alguns divs que o iScroll pode usar:

<div id="wrapper">
  <div id="scroller">
    ... my scrollable content
  </div>
</div>

CSS: Usei a classe Modernizr para "toque" para direcionar minhas alterações de estilo apenas para dispositivos de toque (porque eu só instanciei o iScroll no toque).

.touch #wrapper {
  position: absolute;
  z-index: 1;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  overflow: hidden;
}
.touch #scroller {
  position: absolute;
  z-index: 1;
  width: 100%;
}

JS: Incluí iscroll-probe.js do download do iScroll e, em seguida, inicializei o scroller como abaixo, em que updatePosition é minha função que reage à nova posição de rolagem.

# coffeescript
if Modernizr.touch
  myScroller = new IScroll('#wrapper', probeType: 3)
  myScroller.on 'scroll', updatePosition
  myScroller.on 'scrollEnd', updatePosition

Você tem que usar myScroller para obter a posição atual agora, em vez de olhar para o deslocamento da rolagem. Aqui está uma função tirada de http://markdalgleish.com/presentations/embracingtouch/ (um artigo muito útil, mas um pouco desatualizado agora)

function getScroll(elem, iscroll) {   
  var x, y;

  if (Modernizr.touch && iscroll) {
    x = iscroll.x * -1;
    y = iscroll.y * -1;   
  } else {
    x = elem.scrollTop;
    y = elem.scrollLeft;   
  }

  return {x: x, y: y}; 
}

A única outra pegadinha era que ocasionalmente eu perdia parte da minha página que estava tentando acessar, e ela se recusava a rolar. Eu tinha que adicionar algumas chamadas a myScroller.refresh () sempre que alterava o conteúdo do #wrapper, e isso resolveu o problema.

EDIT: Outra pegadinha foi que o iScroll come todos os eventos de "clique". Ativei a opção de fazer com que o iScroll emita um evento de "toque" e lidei com eles em vez de eventos de "clique". Felizmente, não precisei de muitos cliques na área de rolagem, então isso não era grande coisa.

Melinda Weathers
fonte
1

Desde que o iOS 8 foi lançado, esse problema não existe mais. O evento de rolagem agora é disparado sem problemas no iOS Safari também.

Portanto, se você registrar o scrollmanipulador de eventos e verificar window.pageYOffsetdentro desse manipulador de eventos, tudo funcionará perfeitamente.

Matthias Bohlen
fonte
1
Ele ainda existe em alguns casos de uso, como o uso do Cordova. developer.telerik.com/featured/…
diosney
6
Minha experiência é que isso ainda continua sendo um problema com os dispositivos iOS atuais em 2019.
Chris