Angular 2 Role para cima em Alteração de rota

296

No meu aplicativo Angular 2, quando deslizo para baixo em uma página e clico no link na parte inferior da página, ele muda a rota e me leva para a próxima página, mas não rola para o topo da página. Como resultado, se a primeira página for longa e a segunda página tiver pouco conteúdo, parecerá que a segunda página não possui o conteúdo. Como o conteúdo é visível apenas se o usuário rolar para o topo da página.

Posso rolar a janela para o topo da página em ngInit do componente, mas existe alguma solução melhor que possa lidar automaticamente com todas as rotas no meu aplicativo?

Naveed Ahmed
fonte
20
Desde o Angular 6.1, podemos usar {scrollPositionRestoration: 'enabled'} em módulos carregados avidamente ou apenas no app.module e ele será aplicado a todas as rotas. RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
Manwal 16/03/19
Muito obrigado sua solução funcionou perfeitamente para mim :)
Raphael Godoi
nenhuma pessoa mencionou o foco? é mais importante do que nunca oferecer suporte adequado aos leitores de acessibilidade / tela e, se você simplesmente rolar para o topo sem considerar o foco, o pressionamento de tecla da próxima guia poderá pular para a parte inferior da tela.
Simon_Weaver 9/01

Respostas:

386

Você pode registrar um ouvinte de alteração de rota em seu componente principal e rolar para cima nas alterações de rota.

import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {
    constructor(private router: Router) { }

    ngOnInit() {
        this.router.events.subscribe((evt) => {
            if (!(evt instanceof NavigationEnd)) {
                return;
            }
            window.scrollTo(0, 0)
        });
    }
}
Guilherme Meireles
fonte
11
window.scrollTo(0, 0)é uma document.body.scrollTop = 0;OMI mais concisa e legível.
Mark E. Haase
10
Alguém notou que, mesmo após a implementação, o problema persiste no navegador Safari do Iphone. Alguma ideia?
Rgk
1
@mehaase Parece que sua resposta é a melhor. window.body.scrollTop não funciona para mim na área de trabalho do Firefox. Então obrigado!
precisa saber é o seguinte
3
Isso funcionou para mim, mas interrompe o comportamento padrão do botão "voltar". Voltar deve lembrar a posição de rolagem anterior.
JackKalish
6
Isso funcionou !! Embora I adicionado $("body").animate({ scrollTop: 0 }, 1000);, em vez de window.scrollTo(0, 0)para animar suavizar deslocando-se para cima
Manubhargav
360

Angular 6.1 e posterior :

O Angular 6.1 (lançado em 25/07/2018) adicionou suporte interno para lidar com esse problema, por meio de um recurso chamado "Restauração da posição de rolagem do roteador". Conforme descrito no blog oficial do Angular , você só precisa habilitá-lo na configuração do roteador da seguinte maneira:

RouterModule.forRoot(routes, {scrollPositionRestoration: 'enabled'})

Além disso, o blog afirma "Espera-se que isso se torne o padrão em uma futura versão principal". Até o momento, isso não aconteceu (a partir do Angular 8.2), mas, eventualmente, você não precisará fazer nada no seu código, e isso funcionará corretamente imediatamente.

Você pode ver mais detalhes sobre esse recurso e como personalizar esse comportamento nos documentos oficiais .

Angular 6.0 e anterior :

Enquanto a excelente resposta do @ GuilhermeMeireles corrige o problema original, ele apresenta um novo, quebrando o comportamento normal que você espera ao navegar para trás ou para frente (com os botões do navegador ou via Localização no código). O comportamento esperado é que, quando você voltar para a página, ele permanecerá rolado para baixo no mesmo local em que você clicou no link, mas a rolagem para o topo ao chegar a todas as páginas obviamente quebra essa expectativa.

O código abaixo expande a lógica para detectar esse tipo de navegação, assinando a sequência PopStateEvent do Location e pulando a lógica de rolagem para o topo se a página recém-chegada é resultado de um evento desse tipo.

Se a página da qual você navega for longa o suficiente para cobrir toda a janela de exibição, a posição de rolagem será restaurada automaticamente, mas como @JordanNelson apontou corretamente, se a página for mais curta, será necessário acompanhar a posição de rolagem y original e restaurá-la explicitamente quando você voltar para a página. A versão atualizada do código também abrange esse caso, sempre restaurando explicitamente a posição de rolagem.

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';
import { Location, PopStateEvent } from "@angular/common";

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class MyAppComponent implements OnInit {

    private lastPoppedUrl: string;
    private yScrollStack: number[] = [];

    constructor(private router: Router, private location: Location) { }

    ngOnInit() {
        this.location.subscribe((ev:PopStateEvent) => {
            this.lastPoppedUrl = ev.url;
        });
        this.router.events.subscribe((ev:any) => {
            if (ev instanceof NavigationStart) {
                if (ev.url != this.lastPoppedUrl)
                    this.yScrollStack.push(window.scrollY);
            } else if (ev instanceof NavigationEnd) {
                if (ev.url == this.lastPoppedUrl) {
                    this.lastPoppedUrl = undefined;
                    window.scrollTo(0, this.yScrollStack.pop());
                } else
                    window.scrollTo(0, 0);
            }
        });
    }
}
Fernando Echeverria
fonte
2
Isso deve ser diretamente no componente do aplicativo ou em um único componente usado nele (e, portanto, compartilhado por todo o aplicativo). Por exemplo, incluí-o em um componente da barra de navegação superior. Você não deve ser incluído em todos os seus componentes.
Fernando Echeverria
3
Você pode fazer isso e isso tornará o código mais amplamente compatível com outras plataformas que não sejam de navegador. Consulte stackoverflow.com/q/34177221/2858481 para obter detalhes da implementação.
Fernando Echeverria
3
Se você clicar e segurar o botão voltar / avançar nos navegadores modernos, será exibido um menu que permite navegar para outros locais além do imediatamente anterior / próximo. Esta solução falha se você fizer isso. É um caso de ponta para a maioria, mas vale a pena mencionar.
adamdport
1
Existe uma maneira de ativar a "Restauração da posição de rolagem do roteador" para elementos aninhados ou funciona apenas para body?
vulp 18/11/19
61

No Angular 6.1, agora você pode evitar problemas e passar extraOptionspara o seu RouterModule.forRoot()como um segundo parâmetro e pode especificar scrollPositionRestoration: enabledpara pedir ao Angular para rolar para o topo sempre que a rota for alterada.

Por padrão, você encontrará isso em app-routing.module.ts:

const routes: Routes = [
  {
    path: '...'
    component: ...
  },
  ...
];

@NgModule({
  imports: [
    RouterModule.forRoot(routes, {
      scrollPositionRestoration: 'enabled', // Add options right here
    })
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Documentos oficiais angulares

Abdul Rafay
fonte
3
Mesmo que a resposta acima seja mais descritiva, gosto que esta resposta me diga exatamente onde isso precisa ir
ryanovas
32

Você pode escrever isso de forma mais sucinta, aproveitando o filtermétodo observável :

this.router.events.filter(event => event instanceof NavigationEnd).subscribe(() => {
      this.window.scrollTo(0, 0);
});

Se você estiver com problemas para rolar para o topo ao usar a barra lateral Material Angular 2, isso ajudará. O corpo da janela ou do documento não terá a barra de rolagem; portanto, você precisa obter o sidenavcontêiner de conteúdo e rolar esse elemento; caso contrário, tente rolar a janela como padrão.

this.router.events.filter(event => event instanceof NavigationEnd)
  .subscribe(() => {
      const contentContainer = document.querySelector('.mat-sidenav-content') || this.window;
      contentContainer.scrollTo(0, 0);
});

Além disso, o Angular CDK v6.x agora tem um pacote de rolagem que pode ajudar no manuseio da rolagem.

mtpultz
fonte
2
Ótimo! Para mim que trabalhou -document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
Amir Tugi
Bom pessoal ... na mtpultz & @AmirTugi. Lidando com isso agora, e você acertou em mim, felicidades! Provavelmente, inevitavelmente, acabarei rodando minha própria navegação lateral, pois o Material 2 não funciona bem quando a barra de ferramentas md está na posição: fixa (na parte superior). A menos que vocês tenham idéias .... ????
Tim Harker
Talvez eu tenha encontrado a minha resposta ... stackoverflow.com/a/40396105/3389046 #
9247 Tim Timker
16

Se você tiver renderização no servidor, tome cuidado para não executar o código usando windowsno servidor, onde essa variável não existe. Isso resultaria na quebra de código.

export class AppComponent implements OnInit {
  routerSubscription: Subscription;

  constructor(private router: Router,
              @Inject(PLATFORM_ID) private platformId: any) {}

  ngOnInit() {
    if (isPlatformBrowser(this.platformId)) {
      this.routerSubscription = this.router.events
        .filter(event => event instanceof NavigationEnd)
        .subscribe(event => {
          window.scrollTo(0, 0);
        });
    }
  }

  ngOnDestroy() {
    this.routerSubscription.unsubscribe();
  }
}

isPlatformBrowseré uma função usada para verificar se a plataforma atual em que o aplicativo é renderizado é um navegador ou não. Damos a injeçãoplatformId .

Também é possível verificar a existência da variável windows, para ser seguro, assim:

if (typeof window != 'undefined')
Raptor
fonte
1
Você não precisa injetar PLATFORM_IDno constructore dar esse valor como parâmetro no isPlatformBrowsermétodo de?
Poul Kruijt
1
@PierreDuc Sim, a resposta está errada. isPlatformBrowseré uma função e sempre será verdadeira. Eu editei agora.
Lazar Ljubenović 14/01
Obrigado! Está correto agora! Acabei de verificar a API: github.com/angular/angular/blob/…
Raptor
13

basta facilitar com a ação do clique

no componente principal html, faça referência #scrollContainer

<div class="main-container" #scrollContainer>
    <router-outlet (activate)="onActivate($event, scrollContainer)"></router-outlet>
</div>

no componente principal .ts

onActivate(e, scrollContainer) {
    scrollContainer.scrollTop = 0;
}
SENTOU
fonte
O elemento a ser rolada pode não ser no scrollContainerprimeiro nó, você pode precisar cavar um pouco no objeto, para mim o que ele realmente funcionou foiscrollContainer .scrollable._elementRef.nativeElement.scrollTop = 0
Byron Lopez
13

A Angular introduziu recentemente um novo recurso, o módulo de roteamento angular interno faz alterações como abaixo

@NgModule({
  imports: [RouterModule.forRoot(routes,{
    scrollPositionRestoration: 'top'
  })],
Pran RV
fonte
12

A melhor resposta reside na discussão do Angular GitHub ( Alterar rota não rola para o topo da nova página ).

Talvez você queira ir para o topo apenas nas alterações do roteador raiz (não nas crianças, porque você pode carregar rotas com carga lenta em um conjunto de guias)

app.component.html

<router-outlet (deactivate)="onDeactivate()"></router-outlet>

app.component.ts

onDeactivate() {
  document.body.scrollTop = 0;
  // Alternatively, you can scroll to top by using this other call:
  // window.scrollTo(0, 0)
}

Créditos completos para JoniJnm ( post original )

zurfyx
fonte
8

Você pode adicionar o gancho do ciclo de vida AfterViewInit ao seu componente.

ngAfterViewInit() {
   window.scrollTo(0, 0);
}
stillatmylinux
fonte
7

A partir do Angular 6.1, o roteador fornece uma opção de configuração chamada scrollPositionRestoration, projetada para atender a esse cenário.

imports: [
  RouterModule.forRoot(routes, {
    scrollPositionRestoration: 'enabled'
  }),
  ...
]
Marty A
fonte
4

Se você precisar simplesmente rolar a página para o topo, poderá fazê-lo (não a melhor solução, mas rápido)

document.getElementById('elementId').scrollTop = 0;
Aliaksei
fonte
4

Aqui está uma solução que eu criei. Emparelhei a LocationStrategy com os eventos do roteador. Usando o LocationStrategy para definir um booleano para saber quando um usuário está percorrendo atualmente o histórico do navegador. Dessa forma, não preciso armazenar muitos dados de URL e rolagem y (o que não funciona bem de qualquer maneira, pois cada dado é substituído com base no URL). Isso também resolve o caso extremo quando um usuário decide pressionar o botão voltar ou avançar em um navegador e voltar ou encaminhar várias páginas em vez de apenas uma.

PS: Eu testei apenas na versão mais recente do IE, Chrome, FireFox, Safari e Opera (a partir deste post).

Espero que isto ajude.

export class AppComponent implements OnInit {
  isPopState = false;

  constructor(private router: Router, private locStrat: LocationStrategy) { }

  ngOnInit(): void {
    this.locStrat.onPopState(() => {
      this.isPopState = true;
    });

    this.router.events.subscribe(event => {
      // Scroll to top if accessing a page, not via browser history stack
      if (event instanceof NavigationEnd && !this.isPopState) {
        window.scrollTo(0, 0);
        this.isPopState = false;
      }

      // Ensures that isPopState is reset
      if (event instanceof NavigationEnd) {
        this.isPopState = false;
      }
    });
  }
}
Sal_Vader_808
fonte
4

Essa solução é baseada nas soluções @ FernandoEcheverria e @ GuilhermeMeireles, mas é mais concisa e funciona com os mecanismos popstate fornecidos pelo Angular Router. Isso permite armazenar e restaurar o nível de rolagem de várias navegações consecutivas.

Armazenamos as posições de rolagem para cada estado de navegação em um mapa scrollLevels. Uma vez que há um evento popstate, a identificação do estado que está prestes a ser restaurado é fornecida pelo Angular Router: event.restoredState.navigationId. Isso é usado para obter o último nível de rolagem desse estado scrollLevels.

Se não houver nível de rolagem armazenado para a rota, ela rolará para o topo, como seria de esperar.

import { Component, OnInit } from '@angular/core';
import { Router, NavigationStart, NavigationEnd } from '@angular/router';

@Component({
    selector: 'my-app',
    template: '<ng-content></ng-content>',
})
export class AppComponent implements OnInit {

  constructor(private router: Router) { }

  ngOnInit() {
    const scrollLevels: { [navigationId: number]: number } = {};
    let lastId = 0;
    let restoredId: number;

    this.router.events.subscribe((event: Event) => {

      if (event instanceof NavigationStart) {
        scrollLevels[lastId] = window.scrollY;
        lastId = event.id;
        restoredId = event.restoredState ? event.restoredState.navigationId : undefined;
      }

      if (event instanceof NavigationEnd) {
        if (restoredId) {
          // Optional: Wrap a timeout around the next line to wait for
          // the component to finish loading
          window.scrollTo(0, scrollLevels[restoredId] || 0);
        } else {
          window.scrollTo(0, 0);
        }
      }

    });
  }

}
Simon Mathewson
fonte
Impressionante. Eu tive que fazer uma versão um pouco personalizada para rolar uma div em vez de janela, mas funcionou. Uma diferença fundamental era scrollTopvs scrollY.
BBaysinger
4

Além da resposta perfeita fornecida por @Guilherme Meireles, como mostrado abaixo, você pode ajustar sua implementação adicionando rolagem suave, como mostrado abaixo

 import { Component, OnInit } from '@angular/core';
    import { Router, NavigationEnd } from '@angular/router';

    @Component({
        selector: 'my-app',
        template: '<ng-content></ng-content>',
    })
    export class MyAppComponent implements OnInit {
        constructor(private router: Router) { }

        ngOnInit() {
            this.router.events.subscribe((evt) => {
                if (!(evt instanceof NavigationEnd)) {
                    return;
                }
                window.scrollTo(0, 0)
            });
        }
    }

adicione o snippet abaixo

 html {
      scroll-behavior: smooth;
    }

ao seu styles.css

Ifesinachi Bryan
fonte
1

para iphone / ios safari, você pode embrulhar com um setTimeout

setTimeout(function(){
    window.scrollTo(0, 1);
}, 0);
gordinho
fonte
no meu caso, também era necessário definir o elemento de quebra de página css; height: 100vh + 1px;
tubbsy
1

Oi pessoal, isso funciona para mim no angular 4. Você só precisa fazer referência ao pai para rolar na alteração do roteador`

layout.component.pug

.wrapper(#outlet="")
    router-outlet((activate)='routerActivate($event,outlet)')

layout.component.ts

 public routerActivate(event,outlet){
    outlet.scrollTop = 0;
 }`
Jonas Arguelles
fonte
1
perdoe minha preguiça por não se preocupar em aprender pug, mas você pode traduzir para HTML?
CodyBugstein
0

@Fernando Echeverria great! mas esse código não funciona no roteador hash ou roteador lento. porque eles não acionam alterações de local. pode tentar o seguinte:

private lastRouteUrl: string[] = []
  

ngOnInit(): void {
  this.router.events.subscribe((ev) => {
    const len = this.lastRouteUrl.length
    if (ev instanceof NavigationEnd) {
      this.lastRouteUrl.push(ev.url)
      if (len > 1 && ev.url === this.lastRouteUrl[len - 2]) {
        return
      }
      window.scrollTo(0, 0)
    }
  })
}

Witt Bulter
fonte
0

Usar o Routerpróprio causará problemas que você não pode superar completamente para manter uma experiência consistente do navegador. Na minha opinião, o melhor método é usar apenas um costume directivee deixar isso redefinir a rolagem ao clicar. O bom disso é que, se você estiver do mesmo jeito urlque clicar, a página também voltará ao topo. Isso é consistente com sites normais. O básico directivepode ser algo como isto:

import {Directive, HostListener} from '@angular/core';

@Directive({
    selector: '[linkToTop]'
})
export class LinkToTopDirective {

    @HostListener('click')
    onClick(): void {
        window.scrollTo(0, 0);
    }
}

Com o seguinte uso:

<a routerLink="/" linkToTop></a>

Isso será suficiente para a maioria dos casos de uso, mas posso imaginar alguns problemas que podem surgir disso:

  • Não funciona universaldevido ao uso dewindow
  • Pequeno impacto na velocidade de detecção de alterações, porque é acionado a cada clique
  • Não há como desativar esta diretiva

Na verdade, é muito fácil superar esses problemas:

@Directive({
  selector: '[linkToTop]'
})
export class LinkToTopDirective implements OnInit, OnDestroy {

  @Input()
  set linkToTop(active: string | boolean) {
    this.active = typeof active === 'string' ? active.length === 0 : active;
  }

  private active: boolean = true;

  private onClick: EventListener = (event: MouseEvent) => {
    if (this.active) {
      window.scrollTo(0, 0);
    }
  };

  constructor(@Inject(PLATFORM_ID) private readonly platformId: Object,
              private readonly elementRef: ElementRef,
              private readonly ngZone: NgZone
  ) {}

  ngOnDestroy(): void {
    if (isPlatformBrowser(this.platformId)) {
      this.elementRef.nativeElement.removeEventListener('click', this.onClick, false);
    }
  }

  ngOnInit(): void {
    if (isPlatformBrowser(this.platformId)) {
      this.ngZone.runOutsideAngular(() => 
        this.elementRef.nativeElement.addEventListener('click', this.onClick, false)
      );
    }
  }
}

Isso leva em consideração a maioria dos casos de uso, com o mesmo uso do básico, com a vantagem de ativar / desativar:

<a routerLink="/" linkToTop></a> <!-- always active -->
<a routerLink="/" [linkToTop]="isActive"> <!-- active when `isActive` is true -->

comerciais, não leia se não quiser ser anunciado

Outra melhoria pode ser feita para verificar se o navegador suporta ou não passiveeventos. Isso complicará um pouco o código e ficará um pouco obscuro se você quiser implementar tudo isso em suas diretivas / modelos personalizados. Foi por isso que escrevi uma pequena biblioteca que você pode usar para resolver esses problemas. Para ter a mesma funcionalidade acima e com o passiveevento adicionado , você pode alterar sua diretiva para isso, se você usar a ng-event-optionsbiblioteca. A lógica está dentro do click.pnbouvinte:

@Directive({
    selector: '[linkToTop]'
})
export class LinkToTopDirective {

    @Input()
    set linkToTop(active: string|boolean) {
        this.active = typeof active === 'string' ? active.length === 0 : active;
    }

    private active: boolean = true;

    @HostListener('click.pnb')
    onClick(): void {
      if (this.active) {
        window.scrollTo(0, 0);
      }        
    }
}
Poul Kruijt
fonte
0

Isso funcionou para mim melhor em todas as alterações de navegação, incluindo a navegação por hash

constructor(private route: ActivatedRoute) {}

ngOnInit() {
  this._sub = this.route.fragment.subscribe((hash: string) => {
    if (hash) {
      const cmp = document.getElementById(hash);
      if (cmp) {
        cmp.scrollIntoView();
      }
    } else {
      window.scrollTo(0, 0);
    }
  });
}
Jorg Janke
fonte
0

A principal idéia por trás desse código é manter todos os URLs visitados junto com os respectivos dados de rolagemY em uma matriz. Sempre que um usuário abandona uma página (NavigationStart), essa matriz é atualizada. Sempre que um usuário entra em uma nova página (NavigationEnd), decidimos restaurar a posição Y ou não, dependendo de como chegamos a esta página. Se uma referência em alguma página foi usada, rolamos para 0. Se os recursos de retrocesso do navegador foram usados, rolamos para Y salvos em nossa matriz. Desculpe pelo meu Inglês :)

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Location, PopStateEvent } from '@angular/common';
import { Router, Route, RouterLink, NavigationStart, NavigationEnd, 
    RouterEvent } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';

@Component({
  selector: 'my-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit, OnDestroy {

  private _subscription: Subscription;
  private _scrollHistory: { url: string, y: number }[] = [];
  private _useHistory = false;

  constructor(
    private _router: Router,
    private _location: Location) {
  }

  public ngOnInit() {

    this._subscription = this._router.events.subscribe((event: any) => 
    {
      if (event instanceof NavigationStart) {
        const currentUrl = (this._location.path() !== '') 
           this._location.path() : '/';
        const item = this._scrollHistory.find(x => x.url === currentUrl);
        if (item) {
          item.y = window.scrollY;
        } else {
          this._scrollHistory.push({ url: currentUrl, y: window.scrollY });
        }
        return;
      }
      if (event instanceof NavigationEnd) {
        if (this._useHistory) {
          this._useHistory = false;
          window.scrollTo(0, this._scrollHistory.find(x => x.url === 
          event.url).y);
        } else {
          window.scrollTo(0, 0);
        }
      }
    });

    this._subscription.add(this._location.subscribe((event: PopStateEvent) 
      => { this._useHistory = true;
    }));
  }

  public ngOnDestroy(): void {
    this._subscription.unsubscribe();
  }
}
Vladimir Turygin
fonte
0

window.scrollTo()não funciona para mim no Angular 5, então eu usei document.body.scrollTopassim,

this.router.events.subscribe((evt) => {
   if (evt instanceof NavigationEnd) {
      document.body.scrollTop = 0;
   }
});
Rohan Kumar
fonte
0

Se você estiver carregando componentes diferentes com a mesma rota, poderá usar o ViewportScroller para obter a mesma coisa.

import { ViewportScroller } from '@angular/common';

constructor(private viewportScroller: ViewportScroller) {}

this.viewportScroller.scrollToPosition([0, 0]);
arenoso
fonte
0

window scroll top
Ambos window.pageYOffset e document.documentElement.scrollTop retornam o mesmo resultado em todos os casos. window.pageYOffset não é suportado abaixo do IE 9.

app.component.ts

import { Component, HostListener, ElementRef } from '@angular/core';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent  {
  isShow: boolean;
  topPosToStartShowing = 100;

  @HostListener('window:scroll')
  checkScroll() {

    const scrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;

    console.log('[scroll]', scrollPosition);

    if (scrollPosition >= this.topPosToStartShowing) {
      this.isShow = true;
    } else {
      this.isShow = false;
    }
  }

  gotoTop() {
    window.scroll({ 
      top: 0, 
      left: 10, 
      behavior: 'smooth' 
    });
  }
}

app.component.html

<style>
  p {
  font-family: Lato;
}

button {
  position: fixed;
  bottom: 5px;
  right: 5px;
  font-size: 20px;
  text-align: center;
  border-radius: 5px;
  outline: none;
}
  </style>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>
<p>
  Lorem ipsum dolor sit, amet consectetur adipisicing elit. Minus, repudiandae quia. Veniam amet fuga, eveniet velit ipsa repudiandae nemo? Sit dolorem itaque laudantium dignissimos, rerum maiores nihil ad voluptates nostrum.
</p>

<button *ngIf="isShow" (click)="gotoTop()">👆</button>
yogesh waghmare
fonte