Esses dias tentei implementar uma forma de mostrar aos usuários a transição das páginas na aplicação, para isso fui procurar no google e por incrível que pareça conseguia encontrar uma solução em angular. Mas após uma pesquisa extensiva consegui criar a melhor solução pra este desafio.
Então respondendo a pergunta titulo do artigo, a resposta para a criação do page loader é o Router events, sempre que ocorre uma mudança como navegar para outra página, passar parâmetros a URL e outras relacionadas a rota, um evento é disparado, então para implementar a solução cabe a nós olhar para os eventos certos.
Para resolver o desafio separei a explicação em quatro pontos principais, a aplicação, a lógica das rotas e o loader.
1. Aplicação
Nesse ponto criaremos a aplicação que usaremos para implementar o loader, e para isso usaremos o angular CLI.
ng new page-loader --routing
O comando acima inicia um novo projeto de angular com o nome page-loader com as configurações iniciais de rotas.
Continuando criaremos três rotas novas para a aplicação, a page-one, page-two e page-three sendo elas lazy loaded. Vale notar que as rotas a serem criadas devem ser lazy loaded, tanto por questões de performance, como para que o exemplo funcione como esperado. Para isso criaremos as novas rotas com os comandos abaixo:
ng generate module page-one --route page-one --module app.module
ng generate module page-two --route page-two --module app.module
ng generate module page-three --route page-three --module app.module
Tendo todos esses comandos executados com sucesso a estrutura da sua aplicação deve estar parecida com essa:
E assim fica o app-routing.module.ts
:
import { NgModule } from '@angular/core'
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
const routes: Routes = [
{path: '', component: HomeComponent},
{
path: 'second-page',
loadChildren: () => import('./second-page/second-page.module').then(m => m.SecondPageModule)
},
{
path: 'third-page',
loadChildren: () => import('./third-page/third-page.module').then(m => m.ThirdPageModule)
},
{
path: 'first-page',
loadChildren: () => import('./first-page/first-page.module').then(m => m.FirstPageModule)
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
;
Tendo a aplicação já organizada, já podes adicionar alguns textos e alguns estilos para as paginas para ter um ar mais agradável, ou podes também pegar os códigos que eu usei para esse projeto direto do meu github.
2. Lógica
Com a aplicação já criada, focaremos agora na mágica da coisa, para isso escutaremos aos eventos das rotas do angular no elemento mais acima da aplicação, o app.component.ts
. O angular router dispõe de eventos do seu ciclo de vida, desde o inicio de uma navegação até o seu termino, como podes ver através do link, mas para o nosso caso, nós apenas olharemos para três desses eventos:
- NavigationStart: Ocorre quando é iniciado uma nova navegação;
- NavegationEnd: Ocorre quando uma navegação é concluída com sucesso;
- NavigationError: Ocorre quando há um erro durante a navegação.
A resposta para o page loader está nos eventos acima, ao escutá-los podemos mudar o estado da nossa aplicação de forma dinâmica, ou seja quando estiver a iniciar uma navegação, mostraremos o loader e o mesmo pode ser removido após o termino ou erro durante a navegação. Tendo isso em conta o assim fica o nosso app.component.ts
:
import { Component } from '@angular/core'
import { Event, NavigationEnd, NavigationError, NavigationStart, Router } from '@angular/router';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less']
})
export class AppComponent {
loading = false;
constructor(private router: Router){
this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationStart) {
this.loading = true;
}
if (event instanceof NavigationEnd || event instanceof NavigationError) {
this.loading = false;
}
})
}
}
;
3. Loader
Como havia mencionado, o loader estará no componente mais acima da aplicação, assim o mesmo não será removido do dom durante a navegação, e sim será controlado pelo componente mais acima, o app.component.ts
. Então colocaremos o nosso loader diretamente no app.component.html
.
<!-- div para mostrar a animação de loading --
<div *ngIf="loading" class="page-loading"></div>
<app-navbar></app-navbar>
<div class="container">
<router-outlet></router-outlet>
</div>
A variável loading foi criada no app component, e é alterada de acordo com estado da rota, então, enquanto estivermos a navegar o page loader será mostrado e após terminar a navegação o mesmo será ágora já temos tudo quase pronto para o nosso page loader, só falta a animação e para isso eu criei uma animação do tipo progress loader inspirado no youtube. Mas podes usar qualquer uma a sua escolha para mostrar na tela enquanto a sua pagina é carregada.
.page-loading
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 10px;
z-index: 1234;
background-color: transparent;
&::after {
content: "";
position: absolute;
left: 0;
background-color: #77befc;
width: 100%;
height: 100%;
animation: load 3s;
}
}
@keyframes load {
0% {width: 0;}
10% {width: 20%;}
25% {width: 40%;}
50% {width: 60%;}
75% {width: 75%;}
100% {width: 100%;}
}
Resultado final
Considerações finais
Pelo facto da aplicação do exemplo ser simples demais, pode ser difícil de ver o loader em ação, mas se a sua aplicação for mais grande e complexa, está solução te ajudará a dar uma melhor experiencia aos seus utilizadores, já que os mesmos agora terão um feedback agradável quando estiverem a navegar pelas paginas da sua aplicação.
Chegando até aqui, espero que este resultado tenha te ajudado assim como me ajudou.
Dê uma olhada no meu portfólio kelven.dev tem muita coisa interessante por lá.
Top comments (0)