Como obter a posição da barra de rolagem com Javascript?

188

Estou tentando detectar a posição da barra de rolagem do navegador com JavaScript para decidir onde está a exibição atual da página. Meu palpite é que preciso detectar onde está o polegar na pista e, em seguida, a altura do polegar como uma porcentagem da altura total da pista. Estou complicando demais ou o JavaScript oferece uma solução mais fácil que essa? Alguma idéia em termos de código?

Paulo
fonte

Respostas:

207

Você pode usar element.scrollTope element.scrollLeftobter o deslocamento vertical e horizontal, respectivamente, que foram rolados. elementpode ser document.bodyse você se importa com a página inteira. Você pode compará-lo element.offsetHeighte element.offsetWidth(novamente, elementpode ser o corpo) se precisar de porcentagens.

Max Shawabkeh
fonte
2
Qual navegador você está usando? Obter o corpo é feito de maneira diferente em diferentes navegadores ( elemente document.bodyforam apenas exemplos). Consulte howtocreate.co.uk/tutorials/javascript/browserwindow para obter detalhes.
Max Shawabkeh
8
Eu consegui me dar o valor correto no Firefox 3.6 com window.pageYOffset, mas não consigo fazer nada funcionar no IE7. Tentou window.pageYOffset, document.body.scrollTop, document.documentElement.scrollTop,element.scrollTop
Paul
1
scrollTop só funcionou para mim quando adicionei colchetes ... $ (". scrollBody"). scrollTop ()
maia
9
Se você estiver lidando com o elemento 'window', poderá usar window.scrollY em vez de window.scrollTop
Janis Jansen
6
Acho que a posição da rolagem não está definida document.bodyna maioria dos navegadores modernos - geralmente está definida document.documentElementagora. Consulte bugs.chromium.org/p/chromium/issues/detail?id=157855 para obter a transição do Chrome.
Fzzfzzfzz
134

Eu fiz isso para um <div>no Chrome.

elemento .scrollTop - são os pixels ocultos na parte superior devido à rolagem. Sem rolagem, seu valor é 0.

elemento .scrollHeight - são os pixels de toda a div.

elemento .clientHeight - são os pixels que você vê no seu navegador.

var a = element.scrollTop;

será a posição.

var b = element.scrollHeight - element.clientHeight;

será o valor máximo para scrollTop .

var c = a / b;

será a porcentagem de rolagem [de 0 a 1] .

Gatsby
fonte
Obrigado! Provavelmente não de 0 a 1, já que você não pode realmente rolar para a parte inferior do elemento, geralmente - certo?
3
Isso está quase certo. para var b, você deve subtrair window.innerHeight e não element.clientHeight.
Kahless
51
document.getScroll = function() {
    if (window.pageYOffset != undefined) {
        return [pageXOffset, pageYOffset];
    } else {
        var sx, sy, d = document,
            r = d.documentElement,
            b = d.body;
        sx = r.scrollLeft || b.scrollLeft || 0;
        sy = r.scrollTop || b.scrollTop || 0;
        return [sx, sy];
    }
}

retorna uma matriz com dois inteiros- [scrollLeft, scrollTop]

Kennebec
fonte
4
Mostrar como usar essa função com um exemplo teria sido ótimo.
user18490
1
Eu acho que você pode usar este lastscroll = getScroll (); window.scrollTo (lastscroll [0], lastscroll [1]);
Dinesh Rajan
Funciona muito bem, mas mudei o retorno para um objeto com as teclas x e y, pois isso faz um pouco mais de sentido para mim.
xd6_
Editado após o comentário de @ user18490.
Davide Cannizzo
ReferenceError: Não foi possível encontrar a variável: element
Jonny
32

É tipo isso :)

window.addEventListener("scroll", function (event) {
    var scroll = this.scrollY;
    console.log(scroll)
});
Brayan Pastor
fonte
11

Resposta para 2018 :

A melhor maneira de fazer isso é usar a API Intersection Observer .

A API Intersection Observer fornece uma maneira de observar assincronamente alterações na interseção de um elemento de destino com um elemento ancestral ou com a viewport de um documento de nível superior.

Historicamente, detectar a visibilidade de um elemento ou a visibilidade relativa de dois elementos em relação um ao outro tem sido uma tarefa difícil para a qual as soluções não são confiáveis ​​e estão sujeitas a causar lentidão no navegador e nos sites que o usuário está acessando. Infelizmente, à medida que a web amadureceu, a necessidade desse tipo de informação aumentou. As informações de interseção são necessárias por vários motivos, como:

  • O carregamento lento de imagens ou outro conteúdo como uma página é rolado.
  • Implementar sites da "rolagem infinita", onde cada vez mais conteúdo é carregado e renderizado à medida que você rola, para que o usuário não precise folhear as páginas.
  • Relatórios de visibilidade de anúncios para calcular receitas de anúncios.
  • Decidir se deve ou não executar tarefas ou processos de animação com base em se o usuário verá ou não o resultado.

A implementação da detecção de interseção no passado envolvia manipuladores de eventos e loops que chamavam métodos como Element.getBoundingClientRect () para criar as informações necessárias para cada elemento afetado. Como todo esse código é executado no thread principal, mesmo um deles pode causar problemas de desempenho. Quando um site é carregado com esses testes, as coisas podem ficar completamente feias.

Veja o seguinte exemplo de código:

var options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
}

var observer = new IntersectionObserver(callback, options);

var target = document.querySelector('#listItem');
observer.observe(target);

A maioria dos navegadores modernos oferece suporte ao IntersectionObserver , mas você deve usar o polyfill para compatibilidade com versões anteriores.

str
fonte
8

se você se importa com a página inteira. você pode usar isso:

document.body.getBoundingClientRect().top

lemospy
fonte
1
use document.body
danial dezfouli
3

Se você estiver usando jQuery, existe uma função perfeita para você: .scrollTop ()

doc here -> http://api.jquery.com/scrollTop/

nota: você pode usar esta função para recuperar OU definir a posição.

veja também: http://api.jquery.com/?s=scroll

Simão, o salmão
fonte
25
Por que responder a uma pergunta sobre JS com uma biblioteca para JS, quando é completamente possível e até conveniente fazê-lo em JS bruto? Você está apenas pedindo a ele que adicione mais tempo de carregamento e use algum armazenamento para algo completamente desnecessário. Além disso, desde quando o javascript começou a significar JQuery?
DaemonOfTheWest
4
se você perguntar individualmente, nunca gostei do jQuery e ainda não respondi a essa pergunta, mas no Vanilla JS já existem respostas dadas por outros colegas, o que é um problema se alguém tiver adicionado um tempero saboroso nesse segmento. (Ele já mencionou que se você estiver usando jQuery)
Ravinder Payal
@ R01010010 é porque hoje em dia o JQuery é inútil e contraproducente, todos os recursos do JQuery são fáceis de implementar com o VanilaJS, você também fica dependente do que está dentro do JQuery, com novos recursos disponíveis no VanillsaJS, você como programador, não atualiza, apenas como exemplo Hoje em dia há uma nova API no VanillaJS chamada fetch que substituiu o XHR antigo. Se você estivesse no mundo do JQuery, nunca verá os benefícios na busca e continuará usando o jQuery.ajax (). Minha opinião pessoal é que as pessoas que continuam usando JQuery é porque eles pararam de aprender. Também o VanillaJS é mais rápido vanilla-js.com
John Balvin Arias
@JohnBalvinArias falando sobre busca, o que há no ie11 ou mesmo Edge?
Ben
Corrija-me se eu estiver errado, mas a busca não funciona corretamente no "moderno", isto é, e ainda é amplamente utilizado. Se eu estivesse usando o jquery, dificilmente seria encorajado a seguir em frente #
Ben
3

Aqui está a outra maneira de obter a posição de rolagem

const getScrollPosition = (el = window) => ({
  x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
  y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
Gor
fonte
0

Eu acho que a seguinte função pode ajudar a ter valores de coordenadas de rolagem:

const getScrollCoordinate = (el = window) => ({
  x: el.pageXOffset || el.scrollLeft,
  y: el.pageYOffset || el.scrollTop,
});

Eu recebi essa idéia dessa resposta com uma pequena mudança.

AmerllicA
fonte