Role para o elemento ao clicar em Angular 4

99

Quero poder rolar para um destino quando um botão for pressionado. Eu estava pensando algo assim.

<button (click)="scroll(#target)">Button</button>

E no meu component.ts método parecido.

scroll(element) {
    window.scrollTo(element.yPosition)
}

Sei que o código acima não é válido mas apenas para mostrar o que estava pensando. Acabei de começar a aprender Angular 4 sem nenhuma experiência anterior com Angular. Tenho procurado algo assim, mas todos os exemplos estão em AngularJs, que difere muito do Angular 4

BuZZ-dEE
fonte
1
Sua sintaxe não tem problemas, mas você precisa definir o que é #target.
wannadream
1
Então isso deve funcionar? Quando eu uso um número arbitrário e chamo window.scrollTo (500) em minha função, nada acontece. Eu estava pensando que esse elemento seria um HTMLElement
Certo, no entanto, o que é #target, o Angular não resolverá? Você pode testar scroll () sem nenhum parâmetro primeiro.
wannadream
Sim, eu tentei (click) = "scroll ()" no meu botão e window.scrollTo (0, 500) no componente, mas nada acontece
2
Mas quando eu faço window.scrollTo (0, 500) no construtor com um atraso de

Respostas:

150

Você poderia fazer assim:

<button (click)="scroll(target)"></button>
<div #target>Your target</div>

e então em seu componente:

scroll(el: HTMLElement) {
    el.scrollIntoView();
}

Editar: vejo comentários informando que isso não funciona mais devido ao elemento ser indefinido. Eu criei um exemplo StackBlitz em Angular 7 e ainda funciona. Alguém pode dar um exemplo em que não funciona?

Frank Modica
fonte
Por alguma razão, executar esse código exato não faz nada para mim. Mesmo um window.scrollTo (0, 500) codificado não faz nada
1
@ N15M0_jk Sim, há também um objeto que você pode passar com outras opções, dependendo do que você precisa. developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
Frank Modica
1
@Anthony Ele permite que você faça referência ao elemento que deseja passar para a scrollfunção no componente. Observe que o evento de clique chama scroll(target). Se você quiser obter acesso ao elemento de dentro do componente sem ter que passar o elemento, você pode usar @ViewChild.
Frank Modica
2
Funciona bem comigo agora. Mas antes eu cometi um erro bobo e usei em id="target"vez de #targete me deu "erro el é indefinido"!
yashthakkar1173
1
Acredito que o erro indefinido aconteça se o elemento com o #targetestiver dentro de um *ngIf, mas deve funcionar se você usar o @ViewChildmétodo no link de @abbastec
espetacularbob
46

Na verdade, existe uma maneira pura de javascript de fazer isso sem usar setTimeoutourequestAnimationFrame ou jQuery.

Resumindo, encontre o elemento em scrollView para o qual deseja rolar e use scrollIntoView.

el.scrollIntoView({behavior:"smooth"});

Aqui está um plunkr .

Jon
fonte
2
Duas maneiras pelas quais essa resposta é diferente: 1. Esta é uma rolagem suave animada, não um salto. 2. Esta resposta não rola uma janela, mas move uma exibição de rolagem dentro de uma janela. Por exemplo, se você tiver uma visualização de rolagem horizontal dentro da janela. Verifique o plunkr para obter um exemplo.
Jon
1
scrollIntoViewOptions de scrollIntoView (o objeto como argumento) só é compatível com Firefox no momento.
Jesús Fuentes
Funciona bem para Chrome e Firefox, mas não para Safari.
Yamashiro Rion
45

Aqui está como fiz isso usando o Angular 4.

Modelo

<div class="col-xs-12 col-md-3">
  <h2>Categories</h2>
  <div class="cat-list-body">
    <div class="cat-item" *ngFor="let cat of web.menu | async">
      <label (click)="scroll('cat-'+cat.category_id)">{{cat.category_name}}</label>
    </div>
  </div>
</div>

adicione esta função ao componente.

scroll(id) {
  console.log(`scrolling to ${id}`);
  let el = document.getElementById(id);
  el.scrollIntoView();
}
LH7
fonte
Você não definiu elementRefs ou IDs de HTML em seu modelo. Onde exatamente está o elemento 'cat -' + cat.category_id para o qual você está rolando?
Keegan
1
Esta é uma resposta melhor. Você pode colocar a rolagem em outro componente.
Dale Nguyen
Esta deve ser a resposta aceita. Trabalhando para Angular 9.
Dezesseis
30

No Angular 7 funciona perfeito

HTML

<button (click)="scroll(target)">Click to scroll</button>
<div #target>Your target</div>

Em componente

  scroll(el: HTMLElement) {
    el.scrollIntoView({behavior: 'smooth'});
  }
Robert S.
fonte
2
bônus para {comportamento: 'smooth'}
Receitas Squapl
Está funcionando para mim .. agradecimento especial por {comportamento: 'smooth'}
Vibhu kumar
Isso não funcionará se #targetestiver definido após o botão, o que é relevante se você tiver um cabeçalho flutuante, por exemplo ...
Jonathan
21

Jon tem a resposta certa e isso funciona em meus projetos angulares 5 e 6.

Se eu quiser clicar para rolar suavemente da barra de navegação para o rodapé:

<button (click)="scrollTo('.footer')">ScrolltoFooter</button>
<footer class="footer">some code</footer>

scrollTo(className: string):void {
   const elementList = document.querySelectorAll('.' + className);
   const element = elementList[0] as HTMLElement;
   element.scrollIntoView({ behavior: 'smooth' });
}

Como eu queria rolar de volta para o cabeçalho do rodapé, criei um serviço no qual essa função está localizada e o injetei nos componentes da barra de navegação e do rodapé e passei 'cabeçalho' ou 'rodapé' quando necessário. apenas lembre-se de dar às declarações de componente os nomes de classe usados:

<app-footer class="footer"></app-footer>
Stephen E.
fonte
15

Outra maneira de fazer isso no Angular:

Markup:

<textarea #inputMessage></textarea>

Adicionar ViewChild()propriedade:

@ViewChild('inputMessage')
inputMessageRef: ElementRef;

Role para qualquer lugar que quiser dentro do componente usando a scrollIntoView()função:

this.inputMessageRef.nativeElement.scrollIntoView();
Schnapz
fonte
10

Você pode rolar para qualquer elemento ref em sua visão usando o bloco de código abaixo. Observe que o destino (id do elementref ) pode estar em qualquer tag html válida.

Na visualização (arquivo html)

<div id="target"> </div>
<button (click)="scroll()">Button</button>
 

  

no .tsarquivo,

scroll() {
   document.querySelector('#target').scrollIntoView({ behavior: 'smooth', block: 'center' });
}
Ifesinachi Bryan
fonte
7

Você pode conseguir isso usando a referência a um elemento DOM angular da seguinte maneira:

Aqui está o exemplo em stackblitz

o modelo de componente:

<div class="other-content">
      Other content
      <button (click)="element.scrollIntoView({ behavior: 'smooth', block: 'center' })">
        Click to scroll
      </button>
    </div>
    <div id="content" #element>
      Some text to scroll
</div>
Andres Gardiol
fonte
6

No Angular, você pode usar ViewChilde ElementRef: dar ao seu elemento HTML uma referência

<div #myDiv > 

e dentro do seu componente:

import { ViewChild, ElementRef } from '@angular/core';
@ViewChild('myDiv') myDivRef: ElementRef;

você pode usar this.myDivRef.nativeElementpara chegar ao seu elemento

M.Amer
fonte
Esta é uma boa solução, mas o problema é que só funciona quando recarrego a guia, mas não com o routerLink. Alguma solução para esse problema galera?
Ahsan
-8

Eu fiz algo parecido com o que você está pedindo apenas usando jQuery para encontrar o elemento (como document.getElementById(...)) e usando a .focus()chamada.

Kenneth Salomon
fonte
3
O jQuery é realmente necessário ao usar o Angular? Parece que o Angular deve ser o suficiente
Não tenho 100% de certeza, mas estava em um ambiente que não foi validado e refatorado para o Angular2, então não procurei muito por uma solução no Angular e apenas fui com algo que sabia que teria acesso.
Kenneth Salomon de
8
Você não deve usar Jquery e Angular
Stefdelec
2
Sim sim, aprendi muito e todos comentam que não devo usar jQuery. Você não está dizendo nada que outras pessoas não comentaram acima de você.
Kenneth Salomon
Votei você pela humildade. Eu gostaria de acrescentar que as respostas do jQuery têm algum valor para aqueles que estão fazendo a transição para estruturas SPA. Mostrando como fazíamos e vendo os comentários recomendando outras soluções.
B2K
-17

Você pode fazer isso usando jquery:

código ts:

    scrollTOElement = (element, offsetParam?, speedParam?) => {
    const toElement = $(element);
    const focusElement = $(element);
    const offset = offsetParam * 1 || 200;
    const speed = speedParam * 1 || 500;
    $('html, body').animate({
      scrollTop: toElement.offset().top + offset
    }, speed);
    if (focusElement) {
      $(focusElement).focus();
    }
  }

Código HTML :

<button (click)="scrollTOElement('#elementTo',500,3000)">Scroll</button>

Aplique isso nos elementos que você deseja rolar:

<div id="elementTo">some content</div>

Aqui está uma amostra stackblitz.

Gns
fonte
1
Exceto isso op está pedindo soluções typescript não arounds de trabalho com uma estrutura obsoleta (baixo votado)
ash
esta é a solução datilografada.
Gns
1
Você não entendeu, sua resposta usa jQuery (devo acrescentar da maneira mais ineficiente) em vez de simplesmente usar ES *. Suas constantes também não declaram seu tipo. É apenas um exemplo ruim com lógica ruim usando jQuery que não é o que foi perguntado.
cinza