2009-09-06 11 views
16

Actualmente mi programa se encuentra en un punto en el que escucha al usuario desplazarse por un elemento determinado, pero también, a veces, desplaza automáticamente este elemento por sí mismo. (No es un desplazamiento gradual, bonito, sino un salto instantáneo. Tiene sentido en contexto, lo juro)Make "scrollLeft"/"scrollTop" cambios no desencadenan scroll event listener

¿Hay alguna manera de hacer que el evento de desplazamiento no se dispare si el desplazamiento se realizó configurando scrollLeft o scrollTop? Mi primer pensamiento fue un interruptor básico, como:

ignoreScrollEvents = true; 
element.scrollLeft = x; 
ignoreScrollEvents = false; 

function onScroll() { 
    if(ignoreScrollEvents) return false; 
} 

pero ya que los eventos no activan de inmediato (perdón, duhh), que no es una solución viable. ¿Qué otro tipo de respuestas podría probar? También estoy usando jQuery, si eso ayuda a algo.

Respuesta

17

método genérico más fácil ? Simplemente reinicie la bandera en el controlador de eventos. Deberá verificar primero si realmente está cambiando el valor, ya que de lo contrario no se disparará un evento - como Rodrigo notes, una buena práctica aquí es factorizar esto en las llamadas funciones "setter":

function setScrollLeft(x) 
{ 
    if (element.scrollLeft != x) 
    { 
    ignoreScrollEvents = true; 
    element.scrollLeft = x; 
    } 
} 

... 

function onScroll() 
{ 
    var ignore = ignoreScrollEvents; 
    ignoreScrollEvents = false; 

    if (ignore) return false; 

    ... 
} 

Pero, dependiendo de sus necesidades, es posible que ya esté almacenando la posición de desplazamiento en algún lugar; si es así, simplemente actualice y verifique eso como su bandera. Algo como:

element.scrollLeft = currentScrollLeft = x; 

... 

function onScroll() 
{ 
    // retrieve element, etc... 

    if (element.scrollLeft == currentScrollLeft) return false; 

    ... 
} 
+0

En mi código, me tocó un problema: a veces sucede que, por ejemplo, scrollLeft ya es 0, entonces mi código también lo establece en 0. Como tal, no se desencadena ningún evento de desplazamiento, y se ignora el siguiente desplazamiento del usuario. (Lo cual es realmente un problema si lo hacen desplazándose con Home, End, etc.) Pero esta es definitivamente una solución cercana, y sabía que me estaba perdiendo algo estúpido en esa implementación falsa. ¡Gracias! – Matchu

+0

Me pregunté sobre eso ... Su mejor opción es verificar si está cambiando el valor antes de configurar la bandera; no lo configure si no lo está.Puede que ya tenga este código dividido en una función separada, pero si no lo hace, hacerlo lo haría más fácil; vea la respuesta de Rodrigo como ejemplo de esto. – Shog9

1

Usted podría constantly check si los cambios scroll position ...

+0

No es una solución bonita, pero si usted dice que los eventos no se disparan de inmediato ... – marcgg

+0

Cuando digo que los eventos no se desencadenan inmediatamente, quiero decir que en general. Si ejecuto esas primeras 3 líneas, todas van y vienen cuando se activa el evento de desplazamiento, ya que así es como funciona el Javascript. – Matchu

+0

Esta solución es más bonita que la solución aceptada, creo. La solución aceptada quiere que hagas una variable global, y se rompería tan pronto como quisieras dos manejadores 'onScroll'. Sin embargo, esta solución no ofrece un UX rápido, por lo que realmente se trata de rocas y lugares difíciles. – jcarpenter2

0

usted podría intentar almacenar la parte superior de su elemento de desplazamiento y emparejar contra la scrollTop cuando entre al OnScroll:

function onScroll(){ 
    var scrollTop = (document.documentElement.scrollTop || document.body.scrollTop), 
    offsetTop = $('selector').offset().top; 
    if(offsetTop > scrollTop){ 
     //user has not scrolled to element so do auto scrolling 
    } 
} 
2

¿Qué tal un setter?

var _preventEvent = false; // set global flag 
 

 
function setScrollTop(amount) { 
 
    _preventEvent = true; // set flag 
 
    document.documentElement.scrollTop = amount * Math.random(); 
 
} 
 

 
function setScrollLeft(amount) { 
 
    _preventEvent = true; // set flag 
 
    document.documentElement.scrollLeft = amount * Math.random(); 
 
} 
 

 
// scroll event listener 
 
window.onscroll = function() { 
 
    console.clear(); 
 
    
 
    if (_preventEvent) { 
 
    _preventEvent = false; // reset flag 
 
    return; 
 
    } 
 
    
 
    console.log('normal scroll'); 
 
}
html{ height:500%; width:500%; } 
 
button{ position:fixed; } 
 
button + button{ top:50px; }
<button onclick=setScrollTop(1000)>Random scrollTop</button> 
 
<button onclick=setScrollLeft(1000)>Random scrollLeft</button>

0

bien, mi solución final, la construcción fuera de Shog9 (no es mi código real, pero mi enfoque):

var oldScrollLeft = element.scrollLeft; 
element.scrollLeft = x; 
if(element.scrollLeft != oldScrollLeft) { 
    ignoreScrollEvents = true; 
} 

function onScroll() { 
    if(!ignoreScrollEvents) performGreatActions(); 
    ignoreScrollEvents = false; 
} 

La sentencia if sólo se establece el indicador ignorar cuando el valor scrollLeft en realidad termina cambiando, por lo que casos como la configuración de 0 a 0 no configuran el indicador de forma incorrecta.

¡Gracias, todo!

+0

por lo que la respuesta correcta es? – Rodrigo

+0

No estoy seguro. ¿Qué es el protocolo aquí? Si utilizo parte de una respuesta y luego la construyo para llegar a la respuesta completa, ¿marcó la mía o la otra? – Matchu

+0

La respuesta aceptada se ha editado para incluir esta advertencia, por lo que ahora coincide con esta respuesta :) ¡Genial! – Matchu

Cuestiones relacionadas