2013-03-08 28 views
6

Ho bisogno di mantenere l'offset di scorrimento di un elemento in sincronia con un altro (la finestra in realtà) e ho difficoltà a farlo durante la fase inerziale "roll off" di scorrimento su Mobile Safari (iPad).Come sincronizzare l'offset di scorrimento di due elementi durante lo scorrimento inerziale

Ho un paio di div con position:fixed; overflow:hidden e ho bisogno di continuare a compensare in sincronia con uno della finestra il loro scorrimento Di solito mi piacerebbe codificarlo come questo (jQuery) (che significa l'intero rotolo del corpo.):

var $win = $(window), 
    $div1 = $(...) 

$win.scroll(function() { 
    $div1.scrollTop($win.scrollTop()) 
}) 

Ma testando l'interfaccia su un iPad, ho notato che il div non veniva aggiornato né durante la fase di tocco, quando si trascina la pagina virtuale con il dito, né durante la fase inerziale, quando si lascia andare e la pagina rallenta fino a fermarsi.

L'ho risolto per la fase di trascinamento registrando il gestore per l'evento touchmove e lo scroll.

Ma non riesco a trovare un modo per risolvere il problema per la fase inerziale. Il div rimane fermo (e va lentamente fuori sincrono con il resto della pagina) finché il movimento inerziale non si ferma completamente, quando l'evento di scorrimento viene finalmente attivato e salta in posizione.

Here's a working demo.

Provate a scorrere su un iPad per vedere il problema "inerziale scolling". Sfortunatamente non sono riuscito a farlo funzionare su jsFiddle, a causa del comportamento strano dell'iPad con lo scorrimento dell'iframe.

Se potessi eseguire un polling solo in quella fase, potrei mantenere una sembianza di sincronizzazione tra i due elementi. Ho provato con setTimeout, setInterval e requestAnimationFrame, ma nessuno di essi si attiva durante la fase di scorrimento inerziale. Sembra che tutto il Javascript si fermi durante quella fase.

Domande:

  • C'è qualche tocco o evento scroll licenziato durante la fase di scrolling inerziale?
  • C'è un qualsiasi modo per eseguire una richiamata Javascript durante quella fase?
  • C'è un modo per sincronizzare l'offset di scorrimento di due elementi (X o Y, non entrambi) usando CSS o qualche altra tecnologia diversa da JS?
+0

Sarebbe utile aggiungere gli elementi div come elementi figlio al livello di scorrimento? –

+0

Cosa intendi per "livello di scorrimento"? L'elemento che scorre è la finestra, cioè l'intero corpo. Le immersioni fisse sono all'interno del corpo, sì, ma hanno "posizione: fissa". – Tobia

+0

Sto fondamentalmente andando alle informazioni che ho qui http://developer.apple.com/library/ios/#documentation/WindowsViews/Conceptual/UIScrollView_pg/CreatingBasicScrollViews/CreatingBasicScrollViews.html # // apple_ref/doc/uid/TP40008179-CH101-SW1 –

risposta

4

OldDrunkenSailor mi ha battuto per suggerire iScroll.

Sfortunatamente, immediatamente iScroll replica lo stesso problema dello scorrimento inerziale nativo - non c'è gestione di eventi durante la fase inerziale.

Ecco una versione del demo con un iScroll scimmia-patch per aggiungere un evento personalizzato che spara anche durante la fase inerziale: https://dl.dropbox.com/u/15943645/scrollingdemo.html

funziona alla grande sulla mia seconda generazione iPad.

JS:

// Disable touch events 
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false); 

// Patch iScroll for position change custom event 
iScroll.prototype._oldPos = iScroll.prototype._pos; 
iScroll.prototype._pos = function(x, y) { 
    this._oldPos(x, y); 
    if (this.options.onPositionChange) this.options.onPositionChange.call(this); 
} 

$(function() { 
    var $win = $(window), 
     $div_cols = $('#cols'), 
     $div_rows = $('#rows'), 
     $div_body = $('#body') 

    // attach scrolling sync handler and execute it once 
    function sync_scroll(e) { 
     $div_cols.scrollLeft(0 - $div_body.position().left); 
     $div_rows.scrollTop(0 - $div_body.position().top); 

    }   

    // initialize iScroll on wrapper div, with position change handler 
    var myScroll = new iScroll('iscroll_wrapper', { 
     bounce: false, 
     onPositionChange: sync_scroll 
    }); 
}) 

CSS:

#iscroll_wrapper { 
    position:absolute; 
    z-index: 1; 
    left: 168px; 
    top:77px; 
    bottom:0px; 
    right:0; 
    overflow:auto; 
} 

#body { 
    position:absolute; 
    z-index: 1; 
    width: 2046px; 
    height: 3376px; 

} 

Nota solo il corpo risponde a toccare gli eventi, ma si può estendere la tecnica alle righe e colonne div per la relazione inversa.

+0

Non avevo pensato di sostituire completamente lo scorrimento nativo con una libreria, ma è una soluzione che ha perfettamente senso. Grazie a entrambi @OldDrunkenSailor e Nick. Bounty assegnato a Nick per la demo di lavoro! – Tobia

0

Trigger quando inizia uno scorrimento. Nota che i dispositivi iOS bloccano la manipolazione del DOM durante lo scorrimento, mettendoli in coda per applicarli al termine dello scorrimento. Stiamo attualmente esaminando i metodi per consentire l'applicazione delle manipolazioni DOM prima dell'avvio di uno scorrimento.

http://jquerymobile.com/demos/1.0rc1/docs/api/events.html#/demos/1.0rc1/docs/api/events.html

Quello è ciò che avevano da dire in rotolo sezione iniziale

+0

Grazie, ma quella correzione non è correlata al mio problema. Questo non è un bug di accelerazione hardware. Non ci sono elementi che scompaiono. Questo è un problema con gli eventi Javascript che non vengono attivati ​​durante la fase di scorrimento "inerziale" automatica. – Tobia

+0

oh avevo l'impressione che fossero solo in ritardo –

+0

è la tua chiamata completa al win.scroll? –

4

iOS in realtà blocca DOM manipolazione e Javascript, mentre lo scorrimento inerziale sta accadendo. Ecco una semplice demo che ho fatto per illustrare la differenza tra lo scorrimento in un normale ambiente desktop rispetto all'iPad: http://jsfiddle.net/notjoelshapiro/LUcR6/.Questo codice ha solo questo JS in esso:

var num = 0; 
function updateNum(){ 
    num++; 
    $('#awesomeDiv').text(num); 
} 
$(window).scroll(updateNum); 

Su di scorrimento si incrementa un numero e la visualizza sulla parte inferiore della pagina. Vedrai che il numero di scorrimento nella parte inferiore dello schermo viene incrementato solo quando il rotolo inerziale si è fermato. Se Javascript stava agendo in background, non si aggiornerebbe fino a quando lo scorrimento terminasse, ma il numero dovrebbe essere incrementato più in alto.

Quindi, per rispondere alle vostre domande in particolare:

C'è qualche tocco o evento scroll licenziato durante la fase di scrolling inerziale?

Negativo, ghostrider.

Esiste un modo per eseguire una richiamata JavaScript durante questa fase?

Vedere sopra.

C'è un modo per sincronizzare l'offset di scorrimento di due elementi (X o Y, non entrambi) utilizzando CSS o qualche altra tecnologia diversa da JS?

Non sapendo bene cosa intendi qui, JS può fare tutto il calcolo matematico di cui hai bisogno, ma dovrà essere quando la spirale inerziale è completata. Ad essere onesti, però, questo potrebbe essere un sintomo di tl; dr dal momento che sono al lavoro in questo momento.

Hai guardato la libreria iScroll? Simula lo scorrimento intertial (o non inerziale) per gli ambienti touch e non touch e ti dà i callback JS durante/dopo "scroll" e "scroll inerziale" e fornisce molte informazioni che puoi utilizzare per calcolare dove ti trovi pagina.

+0

Grazie per la tua ricerca. Non avevo pensato di sostituire completamente lo scorrimento nativo con una libreria, ma è una soluzione che ha perfettamente senso. Spero sia ok che ho assegnato la taglia a Nick per la sua demo di lavoro. – Tobia

+0

Non ti perdonerò mai ma dato che è internet ..... – OldDrunkenSailor