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?
RouterModule.forRoot(appRoutes, { scrollPositionRestoration: 'enabled' })
Respostas:
Você pode registrar um ouvinte de alteração de rota em seu componente principal e rolar para cima nas alterações de rota.
fonte
window.scrollTo(0, 0)
é umadocument.body.scrollTop = 0;
OMI mais concisa e legível.$("body").animate({ scrollTop: 0 }, 1000);
, em vez dewindow.scrollTo(0, 0)
para animar suavizar deslocando-se para cimaAngular 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:
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.
fonte
body
?No Angular 6.1, agora você pode evitar problemas e passar
extraOptions
para o seuRouterModule.forRoot()
como um segundo parâmetro e pode especificarscrollPositionRestoration: enabled
para 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
:Documentos oficiais angulares
fonte
Você pode escrever isso de forma mais sucinta, aproveitando o
filter
método observável :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
sidenav
contêiner de conteúdo e rolar esse elemento; caso contrário, tente rolar a janela como padrão.Além disso, o Angular CDK v6.x agora tem um pacote de rolagem que pode ajudar no manuseio da rolagem.
fonte
document.querySelector('.mat-sidenav-content .content-div').scrollTop = 0;
Se você tiver renderização no servidor, tome cuidado para não executar o código usando
windows
no servidor, onde essa variável não existe. Isso resultaria na quebra de código.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:fonte
PLATFORM_ID
noconstructor
e dar esse valor como parâmetro noisPlatformBrowser
método de?isPlatformBrowser
é uma função e sempre será verdadeira. Eu editei agora.basta facilitar com a ação do clique
no componente principal html, faça referência #scrollContainer
no componente principal .ts
fonte
scrollContainer
primeiro nó, você pode precisar cavar um pouco no objeto, para mim o que ele realmente funcionou foiscrollContainer .scrollable._elementRef.nativeElement.scrollTop = 0
A Angular introduziu recentemente um novo recurso, o módulo de roteamento angular interno faz alterações como abaixo
fonte
A melhor resposta reside na discussão do Angular GitHub ( Alterar rota não rola para o topo da nova página ).
app.component.html
app.component.ts
Créditos completos para JoniJnm ( post original )
fonte
Você pode adicionar o gancho do ciclo de vida AfterViewInit ao seu componente.
fonte
A partir do Angular 6.1, o roteador fornece uma opção de configuração chamada
scrollPositionRestoration
, projetada para atender a esse cenário.fonte
Se você precisar simplesmente rolar a página para o topo, poderá fazê-lo (não a melhor solução, mas rápido)
fonte
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.
fonte
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 estadoscrollLevels
.Se não houver nível de rolagem armazenado para a rota, ela rolará para o topo, como seria de esperar.
fonte
scrollTop
vsscrollY
.Além da resposta perfeita fornecida por @Guilherme Meireles, como mostrado abaixo, você pode ajustar sua implementação adicionando rolagem suave, como mostrado abaixo
adicione o snippet abaixo
ao seu styles.css
fonte
para iphone / ios safari, você pode embrulhar com um setTimeout
fonte
height: 100vh + 1px;
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
layout.component.ts
fonte
@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:
fonte
Usar o
Router
pró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 costumedirective
e deixar isso redefinir a rolagem ao clicar. O bom disso é que, se você estiver do mesmo jeitourl
que clicar, a página também voltará ao topo. Isso é consistente com sites normais. O básicodirective
pode ser algo como isto:Com o seguinte uso:
Isso será suficiente para a maioria dos casos de uso, mas posso imaginar alguns problemas que podem surgir disso:
universal
devido ao uso dewindow
Na verdade, é muito fácil superar esses problemas:
Isso leva em consideração a maioria dos casos de uso, com o mesmo uso do básico, com a vantagem de ativar / desativar:
comerciais, não leia se não quiser ser anunciado
Outra melhoria pode ser feita para verificar se o navegador suporta ou não
passive
eventos. 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 opassive
evento adicionado , você pode alterar sua diretiva para isso, se você usar ang-event-options
biblioteca. A lógica está dentro doclick.pnb
ouvinte:fonte
Isso funcionou para mim melhor em todas as alterações de navegação, incluindo a navegação por hash
fonte
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 :)
fonte
window.scrollTo()
não funciona para mim no Angular 5, então eu useidocument.body.scrollTop
assim,fonte
Se você estiver carregando componentes diferentes com a mesma rota, poderá usar o ViewportScroller para obter a mesma coisa.
fonte
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
app.component.html
fonte