Ver Mensaje Individual
  #8 (permalink)  
Antiguo 08/04/2015, 12:13
Avatar de Alexis88
Alexis88
Philosopher
 
Fecha de Ingreso: noviembre-2011
Ubicación: Tacna, Perú
Mensajes: 5.552
Antigüedad: 12 años, 5 meses
Puntos: 977
Respuesta: saber los pixeles que recorre usuario al hacer scroll

Deberías tener cuidado con esas peticiones asíncronas al hacer scroll, porque puedes llegar a saturar al servidor y generar una experiencia nada agradable para el usuario. En ese caso, es mejor que tengas los contenidos ya cargados y si no quieres que se muestren desde un inicio, solamente los tendrías que ocultar/mostrar según lo que el usuario se haya desplazado con la barra.

Ya que estás intentando mostrar contenido por secciones, pienso que sería más sencillo que tengas un menú estático en la parte superior con la misma cantidad de opciones que secciones tengas, luego, al darle clic —por ejemplo— a la cuarta opción del menú, utilizas el método que te dije y desplazas la barra hasta donde empieza la cuarta sección, para lo cual tienes que hacer un pequeño cálculo. Como el menú sería estático, entonces, no importará en qué sección se encuentre el usuario pues siempre tendrá las opciones a la mano y así no tendrá que utilizar la barra para desplazarse y dirigirse hacia otra sección.

Un pequeño ejemplo:

Código HTML:
Ver original
  1. <nav>
  2.     <li data-seccion = "#sec1">Opción 1</li>
  3.     <li data-seccion = "#sec2">Opción 2</li>
  4.     <li data-seccion = "#sec3">Opción 3</li>
  5. </nav>
  6.  
  7. <div id = "sec1"></div>
  8. <div id = "sec2"></div>
  9. <div id = "sec3"></div>

Código Javascript:
Ver original
  1. var menu = document.querySelector("nav"),
  2.     objetivo, desplazar, temporizador, permitido = true,
  3.     contador = 0, velocidad = 5, subida, bajada;
  4.  
  5. [].forEach.call(menu.querySelectorAll("li"), function(li){
  6.     li.addEventListener("click", function(){
  7.         if (permitido){
  8.             permitido = false;
  9.             objetivo = document.querySelector(this.dataset.seccion);
  10.             desplazar = objetivo.offsetTop - menu.offsetTop - menu.offsetHeight;
  11.             temporizador = setInterval(function(){
  12.                 contador = desplazar > contador ? contador + velocidad : contador - velocidad;
  13.                 window.scrollTo(0, contador);
  14.             }, 1);
  15.         }
  16.     }, false);
  17. });
  18.  
  19. window.addEventListener("scroll", function(){          
  20.     subida = desplazar - this.scrollY;
  21.     bajada = this.scrollY - desplazar;
  22.     contador = this.scrollY;
  23.    
  24.     //Si alcanza el punto exacto
  25.     if (this.scrollY == desplazar){
  26.         clearInterval(temporizador);
  27.         permitido = true;
  28.     }
  29.    
  30.     if ((subida > 0 && subida < velocidad) || (bajada > 0 && bajada < velocidad)){
  31.         clearInterval(temporizador);
  32.        
  33.         //Subida
  34.         if (subida > 0 && subida < velocidad){
  35.             contador = desplazar > contador ? contador + subida : contador - subida;
  36.         }
  37.    
  38.         //Bajada
  39.         if (bajada > 0 && bajada < velocidad){     
  40.             contador = desplazar > contador ? contador + bajada : contador - bajada;
  41.         }      
  42.        
  43.         window.scrollTo(0, contador);
  44.         permitido = true;
  45.     }
  46. }, false);

DEMO

En el documento HTML, tengo un menú de opciones y divisiones en donde mostraré determinado contenido. Cada opción del menú posee un pseudo-atributo en donde se encuentra el id de cada división, acompañado cada uno de una almohadilla o numeral.

En el código JS, tomo al menú y declaro algunas variables que usaré más adelante, entre ellas, la velocidad con la cual desplazaré la barra para así darle un efecto de desplazamiento suave, además, una variable que determinará si está permitido o no el uso de las opciones del menú, esto es para evitar que mientras ocurre el efecto de desplazamiento suave, el usuario pulse otra opción, produciendo un conflicto. El valor de esta última variable iniciará como true para indicar que se puede proceder, cambiará a false cuando se inicie el proceso y volverá a tener el valor booleano true cuando este culmine. Enseguida, mediante un bucle, recorro al conjunto de opciones que posee el menú y, en cada iteración, delego una función por cada vez que se produzca el evento click en cualquiera de las opciones.

Al momento de producirse el referido evento, ejecuto una función, en la cual tomo a la división que deseo mostrar, para lo cual accedo al pseudo-atributo de la opción pulsada y mediante el valor que contiene, tomo a la división que corresponda de acuerdo a su id. Luego, calculo la distancia a desplazarse, la cual deriva de la resta de la distancia que hay desde el tope de la página hasta el tope de la división en cuestión menos la distancia que hay desde el tope de la página hasta el tope del menú menos la altura del menú; de esta forma, el desplazamiento deberá de realizarse hasta que el tope de la división coincida con el borde inferior del menú.

Luego de esto, utilizo un temporizador, en el cual se ejecutará una función cada milésima de segundo. En dicha función, sumo o resto a una variable contadora la cantidad de píxeles determinada en la variable de velocidad, dependiendo esto de si la cantidad a desplazarse es mayor o menor que el valor del contador. En el primer caso, es decir, cuando la cantidad a desplazarse sea mayor al valor del contador, el desplazamiento es hacia abajo, caso contrario, hacia arriba. Seguidamente, utilizo el método scrollTo para desplazar a la barra la cantidad de píxeles que determina el valor actualizado de la variable contadora.

Mientras lo anterior ocurre, delego una función a la ventana, la cual se ejecutará cada vez que se produzca el evento scroll en la misma, es decir, cuando esté ocurriendo un desplazamiento con la barra. En dicha función, tomo la diferencia existente entre la cantidad de píxeles desplazados hasta ese momento (el desplazamiento real se da de píxel en píxel) menos la cantidad de píxeles a desplazarse. Tomo las diferencias en caso se esté de subida o bajada, además, actualizo el valor de la variable contadora con la cantidad de píxeles desplazados hasta ese momento por si al usuario se le ocurre desplazarse manualmente y luego pulsa una de las opciones del menú, así el efecto de desplazamiento suave ocurrirá desde el punto en el que se encuentra y no desde el tope del documento. Enseguida, utilizo tres condiciones para los tres posibles casos: Cuando la cantidad de píxeles desplazados hasta ese momento haya logrado alcanzar el objetivo, cuando sea mayor a cero y menos a la cantidad de píxeles que determina la variable de velocidad (cuando se está desplazando hacia arriba) y cuando sea el caso contrario a este último (cuando se está desplazando hacia abajo).

En el primer caso, lo único que tengo que hacer es detener al temporizador pues, al haberse alcanzado el objetivo, no hay necesidad de seguir desplazando a la barra. Utilizo la palabra reservada return para terminar la ejecución de la función ya que no queda nada más por hacer y así evito realizar la siguiente evaluación de manera innecesaria.

Para el segundo y tercer caso, los cuales se producen porque la cantidad de píxeles a desplazarse (el objetivo) no siempre coincide con la suma que se va realizando entre el contador y la velocidad, es decir, a veces hay que desplazarse 532 píxeles, pero si sumas de 5 en 5, nunca llegarás a dicha cifra, ejecuto un bloque de instrucciones que consiste en lo siguiente: Primero, detengo al temporizador, luego, según sea que esté desplazándome hacia arriba o hacia abajo, sumo o resto a la variable contadora la diferencia que queda por desplazarse, para luego desplazar a la barra dicha cantidad de píxeles y así culminar con el proceso.

Si deseas que el desplazamiento se produzca con mayor velocidad, solo incrementa el valor de la variable de velocidad.

Por si buscas compatibilidad con navegadores antiguos, te dejo algunas opciones:

Saludos
__________________
«Juro por mi vida y mi amor por ella, que jamás viviré para el provecho de otro hombre, ni le pediré a otro hombre que viva para el mío».

Ayn Rand

Última edición por Alexis88; 09/04/2015 a las 02:17 Razón: Mejora