¿Cómo obtengo un elemento para desplazarme a la vista, usando jQuery?

169

Tengo un documento HTML con imágenes en formato de cuadrícula usando <ul><li><img.... La ventana del navegador tiene desplazamiento vertical y horizontal.

Pregunta: Cuando hago clic en una imagen <img>, ¿cómo hago para que todo el documento se desplace a una posición donde está la imagen que acabo de hacer clic top:20px; left:20px?

He tenido una búsqueda aquí para publicaciones similares ... aunque soy bastante nuevo en JavaScript y quiero entender cómo se logra esto por mí mismo.

Nasir
fuente

Respuestas:

192

Como quieres saber cómo funciona, lo explicaré paso a paso.

Primero desea vincular una función como el controlador de clics de la imagen:

$('#someImage').click(function () {
    // Code to do scrolling happens here
});

Eso aplicará el controlador de clics a una imagen con id="someImage". Si desea hacer esto a todas las imágenes, reemplácelas '#someImage'con 'img'.

Ahora para el código de desplazamiento real:

  1. Obtenga las compensaciones de imagen (en relación con el documento):

    var offset = $(this).offset(); // Contains .top and .left
  2. Resta 20 de topy left:

    offset.left -= 20;
    offset.top -= 20;
  3. Ahora anime las propiedades CSS de desplazamiento hacia arriba y desplazamiento hacia la izquierda de <body>y <html>:

    $('html, body').animate({
        scrollTop: offset.top,
        scrollLeft: offset.left
    });
David Tang
fuente
3
Esto solo funciona para diseños simples. No maneja todos los casos de la manera en que lo hace el .scrollIntoViewmétodo W3C cuando los elementos están anidados dentro de múltiples contenedores desbordados.
natevw
2
¿Por qué reinventar la rueda? Element.scrollIntoView(): developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Serge
@Serge porque es un borrador de trabajo que no se ha implementado en todos los navegadores
John Smith
@JohnSmith, lea atentamente el enlace que publiqué, la sección "Compatibilidad del navegador", verá que no hay ningún navegador que no sea compatible con scrollIntoView
Serge
@Serge Lo siento, no me di cuenta, también había scrollIntoViewOption (que es el que no es lo suficientemente ancho). Supongo que es lo suficientemente bueno.
John Smith
377

Hay un método DOM llamado scrollIntoView, que es compatible con todos los principales navegadores, que alineará un elemento con la parte superior / izquierda de la ventana gráfica (o lo más cerca posible).

$("#myImage")[0].scrollIntoView();

En los navegadores compatibles, puede proporcionar opciones:

$("#myImage")[0].scrollIntoView({
    behavior: "smooth", // or "auto" or "instant"
    block: "start" // or "end"
});

Alternativamente, si todos los elementos tienen ID únicos, simplemente puede cambiar la hashpropiedad del locationobjeto para la compatibilidad con el botón de retroceso / avance:

$(document).delegate("img", function (e) {
    if (e.target.id)
        window.location.hash = e.target.id;
});

Después de eso, solo ajuste las propiedades scrollTop/ scrollLeften -20:

document.body.scrollLeft -= 20;
document.body.scrollTop -= 20;
Andy E
fuente
2
¡Gracias! 5 otros artículos SO y lo has clavado perfectamente. Mi caso de uso fue un contenedor en un cuadro de diálogo de arranque que debe desplazarse a la vista.
Stephen Patten
10
Como nota: $("#myImage")[0].scrollIntoView(false);alineará el elemento en la parte inferior de la ventana.
Philipp
1
Cuidado: el comportamiento "suave" no es ampliamente compatible, y scrollIntoViewpuede ser una experiencia confusa para los usuarios sin algún tipo de animación.
Cody Duval
1
@JohnHenckel: eso es incorrecto, incluso IE 5.5 tenía scrollIntoViewcon el parámetro booleano. Intentaré enviar una solicitud de extracción para caniuse.com más tarde.
Andy E
1
Nota: Al usar Chrome, no pude desplazar <td>elementos a la vista, en su lugar tuve que desplazar a su padre ( <tr>) y funcionó.
CrazyTim
13

La solución más simple que he visto

var offset = $("#target-element").offset();
$('html, body').animate({
    scrollTop: offset.top,
    scrollLeft: offset.left
}, 1000);

Tutorial aquí

Matt Watson
fuente
A riesgo de hacerlo menos simple, edité esto para admitir el desplazamiento horizontal también.
jpaugh
7

Existen métodos para desplazar el elemento directamente a la vista, pero si desea desplazarse a un punto relativo desde un elemento, debe hacerlo manualmente:

Dentro del controlador de clics, obtenga la posición del elemento en relación con el documento, reste 20y use window.scrollTo:

var pos = $(this).offset();
var top = pos.top - 20;
var left = pos.left - 20;
window.scrollTo((left < 0 ? 0 : left), (top < 0 ? 0 : top));
Felix Kling
fuente
7

Eche un vistazo al complemento jQuery.scrollTo . Aquí hay una demostración .

Este complemento tiene muchas opciones que van más allá de lo que te ofrece scrollIntoView nativo . Por ejemplo, puede configurar el desplazamiento para que sea suave y luego establecer una devolución de llamada para cuando finalice el desplazamiento.

También puede echar un vistazo a todos los complementos de JQuery etiquetados con "scroll" .

Rob Stevenson-Leggett
fuente
¡Obtuve diferentes compensaciones / posiciones en cada navegador en mi caso, y este complemento me ayudó a solucionarlo! ¡Gracias!
LaurelB
4

Aquí hay un complemento rápido de jQuery para mapear muy bien la funcionalidad integrada del navegador:

$.fn.ensureVisible = function () { $(this).each(function () { $(this)[0].scrollIntoView(); }); };

...

$('.my-elements').ensureVisible();
Robar
fuente
3

Después de la prueba y error, se me ocurrió esta función, también funciona con iframe.

function bringElIntoView(el) {    
    var elOffset = el.offset();
    var $window = $(window);
    var windowScrollBottom = $window.scrollTop() + $window.height();
    var scrollToPos = -1;
    if (elOffset.top < $window.scrollTop()) // element is hidden in the top
        scrollToPos = elOffset.top;
    else if (elOffset.top + el.height() > windowScrollBottom) // element is hidden in the bottom
        scrollToPos = $window.scrollTop() + (elOffset.top + el.height() - windowScrollBottom);
    if (scrollToPos !== -1)
        $('html, body').animate({ scrollTop: scrollToPos });
}
Tono Škoda
fuente
2

Solo un consejo. Funciona solo en firefox

Element.scrollIntoView ();

wp estudiante
fuente
44
Esto funciona para todos los navegadores con parámetros booleanos o sin parámetros. Solo el parámetro de objeto más avanzado es menos compatible.
Risord
De acuerdo con developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView hay una falta general de compatibilidad con el navegador para esto
lfender6445
Ahora es lo suficientemente compatible con Opera Mini: caniuse.com/#search=scrollIntoView
John Magnolia
Hay una serie de polyfills muy livianos para eso.
Martin James
1

Mi interfaz de usuario tiene una lista de desplazamiento vertical de los pulgares dentro de una barra de pulgar. El objetivo era hacer que el pulgar actual estuviera justo en el centro de la barra de pulgar. Partí de la respuesta aprobada, pero descubrí que había algunos ajustes para centrar verdaderamente el pulgar actual. Espero que esto ayude a alguien más.

margen:

<ul id='thumbbar'>
    <li id='thumbbar-123'></li>
    <li id='thumbbar-124'></li>
    <li id='thumbbar-125'></li>
</ul>

jquery:

// scroll the current thumb bar thumb into view
heightbar   = $('#thumbbar').height();
heightthumb = $('#thumbbar-' + pageid).height();
offsetbar   = $('#thumbbar').scrollTop();


$('#thumbbar').animate({
    scrollTop: offsetthumb.top - heightbar / 2 - offsetbar - 20
});
xeo
fuente
0

Sencillos 2 pasos para desplazarse hacia abajo hasta el final o hacia abajo.

Paso 1: obtenga la altura completa de la división desplazable (conversación).

Paso 2: aplique scrollTop en ese div desplazable (conversación) utilizando el valor obtenido en el paso 1.

var fullHeight = $('#conversation')[0].scrollHeight;

$('#conversation').scrollTop(fullHeight);

Los pasos anteriores deben aplicarse para cada anexo en el div de conversación.

Shiva Kumar P
fuente
0

Después de tratar de encontrar una solución que manejara todas las circunstancias (opciones para animar el desplazamiento, rellenar el objeto una vez que se desplaza a la vista, funciona incluso en circunstancias oscuras como en un iframe), finalmente terminé escribiendo mi propia solución para esto. Como parece funcionar cuando muchas otras soluciones fallan, pensé en compartirlo:

function scrollIntoViewIfNeeded($target, options) {

    var options = options ? options : {},
    $win = $($target[0].ownerDocument.defaultView), //get the window object of the $target, don't use "window" because the element could possibly be in a different iframe than the one calling the function
    $container = options.$container ? options.$container : $win,        
    padding = options.padding ? options.padding : 20,
    elemTop = $target.offset().top,
    elemHeight = $target.outerHeight(),
    containerTop = $container.scrollTop(),
    //Everything past this point is used only to get the container's visible height, which is needed to do this accurately
    containerHeight = $container.outerHeight(),
    winTop = $win.scrollTop(),
    winBot = winTop + $win.height(),
    containerVisibleTop = containerTop < winTop ? winTop : containerTop,
    containerVisibleBottom = containerTop + containerHeight > winBot ? winBot : containerTop + containerHeight,
    containerVisibleHeight = containerVisibleBottom - containerVisibleTop;

    if (elemTop < containerTop) {
        //scroll up
        if (options.instant) {
            $container.scrollTop(elemTop - padding);
        } else {
            $container.animate({scrollTop: elemTop - padding}, options.animationOptions);
        }
    } else if (elemTop + elemHeight > containerTop + containerVisibleHeight) {
        //scroll down
        if (options.instant) {
            $container.scrollTop(elemTop + elemHeight - containerVisibleHeight + padding);
        } else {
            $container.animate({scrollTop: elemTop + elemHeight - containerVisibleHeight + padding}, options.animationOptions);
        }
    }
}

$target es un objeto jQuery que contiene el objeto que desea desplazar a la vista si es necesario.

options (opcional) puede contener las siguientes opciones pasadas en un objeto:

options.$container- un objeto jQuery que apunta al elemento contenedor de $ target (en otras palabras, el elemento en el dom con las barras de desplazamiento). El valor predeterminado es la ventana que contiene el elemento $ target y es lo suficientemente inteligente como para seleccionar una ventana de iframe. Recuerde incluir los $ en el nombre de la propiedad.

options.padding- el relleno en píxeles para agregar encima o debajo del objeto cuando se desplaza a la vista. De esta manera, no está justo contra el borde de la ventana. El valor predeterminado es 20.

options.instant- si se establece en verdadero, jQuery animate no se usará y el desplazamiento aparecerá instantáneamente en la ubicación correcta. Por defecto es falso.

options.animationOptions- cualquier opción jQuery que desee pasar a la función animada jQuery (consulte http://api.jquery.com/animate/ ). Con esto, puede cambiar la duración de la animación o ejecutar una función de devolución de llamada cuando se completa el desplazamiento. Esto solo funciona si options.instantse establece en falso. Si necesita tener una animación instantánea pero con una devolución de llamada, configure en options.animationOptions.duration = 0lugar de usar options.instant = true.

dallin
fuente