Mousemove / desplazarse al siguiente hash

Agregué el siguiente código para desplazarme con el mouse (desplazarme haciendo clic + arrastrar, no con la rueda del mouse). Hasta ahora, muy bien, funciona como un encanto:

var clicked = false, clickY; $(document).on({ 'mousemove': function(e) { clicked && updateScrollPos(e); }, 'mousedown': function(e) { clicked = true; clickY = e.pageY; }, 'mouseup': function() { clicked = false; $('html').css('cursor', 'auto'); } }); var updateScrollPos = function(e) { $('html').css('cursor', 'row-resize'); $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY)); } 

Estoy tratando de cambiar este comportamiento de desplazamiento para que cada clic direccional + movimiento del mouse de arrastre salte al siguiente / hash más cercano después de, por ejemplo, un arrastre de 10px. En otras palabras, un desplazamiento hacia arriba del mouse debería saltar al siguiente hash sobre la posición actual, desplazarse hacia abajo debería pasar al siguiente siguiente.

Esto no parece estar cubierto por ninguna de las preguntas relacionadas.

Editar:

Creo que necesito reemplazar

 $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY)); 

por partes de la solución en el enlace que sigue. Lamentablemente, esto parece estar por encima de mi nivel de habilidad:

cómo obtener el ancla más cercana desde la posición actual del mouse en el movimiento del mouse

Solución:

Usé la respuesta de Saeed Ataee, muy contento con ese código, pero reemplacé la parte del código de la rueda del mouse con la siguiente que ya tenía en su lugar, simplemente funcionó mejor de mi lado (estoy seguro de que está bien, solo da una alternativa aquí):

 $('#nav').onePageNav(); var $current, flag = false; $('body').mousewheel(function(event, delta) { if (flag) { return false; } $current = $('div.current'); if (delta > 0) { $prev = $current.prev(); if ($prev.length) { flag = true; $('body').scrollTo($prev, 1000, { onAfter : function(){ flag = false; } }); $current.removeClass('current'); $prev.addClass('current'); } } else { $next = $current.next(); if ($next.length) { flag = true; $('body').scrollTo($next, 1000, { onAfter : function(){ flag = false; } }); $current.removeClass('current'); $next.addClass('current'); } } event.preventDefault(); 

});

Creo que esta es tu respuesta.

 let currentElement = 0, maxLength = $("div[id^='section']").length, changeSw = false; $(document).ready(function() { var clicked = false, clickY; $(document).on({ mousemove: function(e) { clicked && updateScrollPos(e); }, mousedown: function(e) { clicked = true; changeSw = true; clickY = e.pageY; }, mouseup: function() { clicked = false; changeSw = false; $("html").css("cursor", "auto"); } }); var updateScrollPos = function(e) { $("html").css("cursor", "row-resize"); // $(window).scrollTop($(window).scrollTop() + (clickY - e.pageY)); if (changeSw && clickY - e.pageY > 0) { currentElement = (currentElement < maxLength - 1) ? currentElement + 1 : currentElement; changeSw = false; clicked = false; } else if (changeSw && clickY - e.pageY <= 0) { currentElement = currentElement > 0 ? currentElement - 1 : 0; changeSw = false; clicked = false; } console.log(currentElement) $("html, body").animate({ scrollTop: $("#section-" + currentElement).offset().top }, 200 ); }; $(document).on("mousewheel", function(e) { if (e.originalEvent.wheelDelta > 0) { currentElement = currentElement > 0 ? currentElement - 1 : 0; $("html, body").animate({ scrollTop: $("#section-" + currentElement).offset().top }, 200 ); } else { currentElement = currentElement < maxLength - 1 ? currentElement + 1 : currentElement; $("html, body").animate({ scrollTop: $("#section-" + currentElement).offset().top }, 200 ); } }); }); 
    
Section 1




















Section 2




















Section 3




















Section 4

Espero que esto te ayude

 let currentElement = 0, maxLength = $("div[id^='section']").length; $(document).ready(function() { $(document).on("mousewheel", function(e) { if (e.originalEvent.wheelDelta > 0) { currentElement = (currentElement > 0) ? currentElement - 1 : 0; $("html, body").animate({ scrollTop: $("#section-" + currentElement).offset().top }, 200 ); } else { currentElement = (currentElement < maxLength - 1) ? currentElement + 1 : currentElement; $("html, body").animate({ scrollTop: $("#section-" + currentElement).offset().top }, 200 ); } }); }); 
    
Section 1




















Section 2




















Section 3




















Section 4

Veo algunas cosas que debes resolver:

1) Marque y encuentre a qué elementos desea desplazarse

Pon algo así como un atributo o clase de identificación en los elementos a los que te gustaría desplazarte. Con el atributo ID, puede usar la antigua navegación hash URL ( http: // some-url / # some-anchor ) además de su nuevo método para navegar.

Digamos que usa el formato #scroll-to-A , #scroll-to-B , etc. como ID para sus anclajes. A continuación, puede orientar todos los elementos con un ID que contenga la cadena scroll-to usando document.querySelectorAll con esto:

const scrollElements = document.querySelectorAll("[id*='scroll-to']"); .

querySelectorAll no devuelve una matriz Element, sino una NodeList. Puede convertirlo en una matriz usando Array.from(scrollElements) . Puede ser útil saber por el rest del código que estoy presentando.

2) Dada la posición de desplazamiento vertical en la página, encuentre qué elemento debe desplazarse a la vista a continuación

Usando Element.getBoundingClientRect() puedes determinar cuántos píxeles de la parte superior de la pantalla se encuentra un elemento:

 function getTopPositionForElement(el) { return el.getBoundingClientRect().top + window.scrollY; } 

Luego puede calcular qué elemento desplazarse a la siguiente marcando cuál está más cerca de la parte superior de la página. Utilice Array.sort para determinar cuál es el más cercano a la matriz y luego elija el primer elemento de la lista:

 function calculateNextElement(direction) { // Handle the cases for direction here... switch (direction) { case "down": return scrollElements.sort((a, b) => { return getTopPositionForElement(a) > getTopPositionForElement(b) ? -1 : 1; })[0]; case "up": // Fill in here default: // Fill in here } } 

Una cosa que debe agregar aquí es manejar los dos casos de la dirección en que el usuario se desplaza. Esta implementación solo tiene en cuenta el desplazamiento hacia abajo. Quizás esto puede ayudar.

3) Desplazar elemento a la vista

Usando Element.scrollIntoView puede desplazar el elemento a la vista para que sea visible para el usuario. Elegí agregar el desplazamiento “suave” a continuación, pero puede usar otras opciones. Verifique la documentación.

 function scrollElementIntoView(direction) { const next = calculateNextElement(direction); next.scrollIntoView({ behaviour: "smooth" }); } 

4) Capturar movimientos de deslizamiento vertical del mouse

Este parece un poco complicado. Podría usar algo como HammerJS si se siente cómodo usando una biblioteca.

Básicamente, se trata de capturar el mouse en el mousedown y luego en el mouseup , verificando cuántos píxeles ha movido el mouse entre los dos eventos. También sugeriría verificar la velocidad de movimiento entre los dos puntos.

Aquí hay un bash:

 let previousEvent; let time; // Keep track of the position where the user starts dragging document.addEventListener("mousedown", function(event) { previousEvent = event; time = new Date(); }); // When the mouse is released, figure out which direction the mouse went document.addEventListener("mouseup", function(event) { const pixelsY = previousEvent.screenY - event.screenY; const timeTaken = Date.now() - time.getTime(); const speed = pixelsY / timeTaken; let direction; if (speed > 1) { direction = "up"; } else if (speed < -1) { direction = "down"; } else { direction = "tap"; } scrollElementIntoView(direction); }); 

¡Buena suerte!