Como obtenho um elemento para rolar para exibição, usando jQuery?

169

Eu tenho um documento HTML com imagens em um formato de grade usando <ul><li><img.... A janela do navegador possui rolagem vertical e horizontal.

Pergunta: Quando clico em uma imagem <img>, como faço para que todo o documento role para uma posição em que a imagem na qual eu apenas cliquei está top:20px; left:20px?

Eu tive uma busca aqui por posts semelhantes ... embora eu seja bastante novo em JavaScript e queira entender como isso é conseguido por mim mesmo.

Nasir
fonte
Duplicado de: Como rolar para um elemento no jQuery?
Hippietrail 28/11/12

Respostas:

192

Como você quer saber como funciona, vou explicar passo a passo.

Primeiro, você deseja vincular uma função como manipulador de cliques da imagem:

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

Isso aplicará o manipulador de cliques a uma imagem com id="someImage". Se você quiser fazer isso com todas as imagens, substitua '#someImage'por 'img'.

Agora, para o código de rolagem real:

  1. Obtenha as compensações de imagem (relativas ao documento):

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

    offset.left -= 20;
    offset.top -= 20;
  3. Agora anime as propriedades CSS de scroll-top e scroll-left de <body>e <html>:

    $('html, body').animate({
        scrollTop: offset.top,
        scrollLeft: offset.left
    });
David Tang
fonte
3
Isso funciona apenas para layouts simples. Ele não lida com todos os casos da maneira que o .scrollIntoViewmétodo W3C faz quando os elementos são aninhados em vários contêineres transbordando.
Natevw 14/01
2
por que reinventar a roda? Element.scrollIntoView(): developer.mozilla.org/pt-BR/docs/Web/API/Element/scrollIntoView
Serge
@Serge porque é um projecto de trabalho que não tenha sido implementado em todos os navegadores
John Smith
@ JohnSmith, por favor, leia atentamente o link que eu publiquei, a seção "Compatibilidade do navegador", você verá que não há navegador que não seja compatível com o #:scrollIntoView
Serge
@ Surge Desculpe por isso, eu não percebi, havia também scrollIntoViewOption (que é aquele que não é suportado o suficiente). Eu acho que é bom o suficiente.
19419 John Smith
377

Existe um método DOM chamado scrollIntoView, suportado por todos os principais navegadores, que alinhará um elemento com a parte superior / esquerda da viewport (ou o mais próximo possível).

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

Nos navegadores suportados, você pode fornecer opções:

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

Como alternativa, se todos os elementos tiverem IDs exclusivos, você poderá alterar a hashpropriedade do locationobjeto para suporte ao botão voltar / avançar:

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

Depois disso, basta ajustar as propriedades scrollTop/ scrollLeftem -20:

document.body.scrollLeft -= 20;
document.body.scrollTop -= 20;
Andy E
fonte
2
Obrigado! 5 outros artigos da SO e você acertou em cheio. Meu caso de uso era um contêiner em uma caixa de diálogo de autoinicialização que precisava rolar para exibição.
Stephen Patten
10
Como nota: $("#myImage")[0].scrollIntoView(false);alinhará o elemento na parte inferior da janela.
Philipp
1
Cuidado: o comportamento "tranquilo" não é amplamente suportado e scrollIntoViewpode ser uma experiência confusa para usuários sem algum tipo de animação.
Cody Duval
1
@ JohnHenckel: isso está incorreto, mesmo o IE 5.5 teve scrollIntoViewcom o parâmetro booleano. Tentarei enviar uma solicitação de recebimento para caniuse.com mais tarde.
Andy E
1
Nota: Usando o Chrome, eu não conseguia rolar os <td>elementos para exibição, mas precisava rolar o pai ( <tr>) e funcionou.
CrazyTim
13

Solução mais simples que eu já vi

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

Tutorial Aqui

Matt Watson
fonte
Correndo o risco de torná-lo menos simples, editei isso para oferecer suporte à rolagem horizontal também.
jpaugh
7

Existem métodos para rolar o elemento diretamente para a visualização, mas se você desejar rolar para um ponto relativo de um elemento, precisará fazê-lo manualmente:

Dentro do manipulador de cliques, obtenha a posição do elemento em relação ao documento, subtraia 20e 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
fonte
7

Dê uma olhada no plugin jQuery.scrollTo . Aqui está uma demonstração .

Este plugin possui muitas opções que vão além do que scrollIntoView nativo oferece a você. Por exemplo, você pode definir a rolagem como suave e definir um retorno de chamada para quando a rolagem terminar.

Você também pode ver todos os plugins JQuery marcados com "scroll" .

Rob Stevenson-Leggett
fonte
Eu estava obtendo diferentes compensações / posições em todos os navegadores no meu caso, e este plugin ajudou a corrigi-lo para mim! obrigado!
LaurelB
4

Aqui está um rápido plugin do jQuery para mapear bem a funcionalidade do navegador:

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

...

$('.my-elements').ensureVisible();
Roubar
fonte
3

Após tentativa e erro, criei esta função, também funciona com 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 });
}
Tom Škoda
fonte
2

Apenas uma dica. Funciona apenas no Firefox

Element.scrollIntoView ();

aluno wp
fonte
4
Isso está funcionando para todos os navegadores com parâmetro booleano ou sem nenhum parâmetro. Somente parâmetros de objeto mais avançados são menos suportados.
precisa saber é o seguinte
de acordo com developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView há falta geral de suporte do browser para este
lfender6445
É agora bastante bem suportado apenas Opera Mini: caniuse.com/#search=scrollIntoView
John Magnolia
Existem vários polyfills muito leves por aí.
Martin James
1

Minha interface do usuário tem uma lista de rolagem vertical de polegares em uma barra de miniaturas. O objetivo era tornar o polegar atual bem no centro da barra de miniaturas. Comecei com a resposta aprovada, mas descobri que havia alguns ajustes para realmente centralizar o polegar atual. espero que isso ajude outra pessoa.

marcação:

<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
fonte
0

2 etapas simples para rolar para baixo até o final ou o fundo.

Etapa 1: obtenha a altura total da div rolável (conversação).

Etapa 2: aplique scrollTop nessa div rolável (conversação) usando o valor obtido na etapa 1.

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

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

As etapas acima devem ser aplicadas a todos os anexos na div da conversa.

Shiva Kumar P
fonte
0

Depois de tentar encontrar uma solução que lidasse com todas as circunstâncias (opções para animar o pergaminho, percorrendo o objeto depois que ele fosse exibido, funcionasse mesmo em circunstâncias obscuras, como em um iframe), finalmente acabei escrevendo minha própria solução para isso. Como parece funcionar quando muitas outras soluções falharam, pensei em compartilhá-lo:

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 é um objeto jQuery que contém o objeto que você deseja rolar para exibição, se necessário.

options (opcional) pode conter as seguintes opções passadas em um objeto:

options.$container- um objeto jQuery apontando para o elemento que contém $ target (em outras palavras, o elemento no dom com as barras de rolagem). O padrão é a janela que contém o elemento $ target e é inteligente o suficiente para selecionar uma janela iframe. Lembre-se de incluir o $ no nome da propriedade.

options.padding- o preenchimento em pixels para adicionar acima ou abaixo do objeto quando ele é rolado para exibição. Desta forma, não está bem contra a borda da janela. O padrão é 20.

options.instant- se definido como true, o jQuery animate não será usado e a rolagem aparecerá instantaneamente no local correto. O padrão é false.

options.animationOptions- quaisquer opções do jQuery que você deseja passar para a função animada do jQuery (consulte http://api.jquery.com/animate/ ). Com isso, você pode alterar a duração da animação ou executar uma função de retorno de chamada quando a rolagem estiver concluída. Isso funciona apenas se options.instantestiver definido como false. Se você precisar de uma animação instantânea, mas com um retorno de chamada, defina em options.animationOptions.duration = 0vez de usar options.instant = true.

Dallas
fonte