Menu fechado

Crie Transições de Página Asíncronas em JavaScript Puro

Transições de Página

Introdução às Transições de Página

As transições de página desempenham um papel fundamental na experiência do usuário, pois elas podem melhorar a usabilidade e a aparência do aplicativo. Uma transição de página bem projetada pode criar uma sensação de continuidade e fluidez, tornando a navegação mais agradável para os usuários. Neste artigo, vamos explorar como criar um sistema de transição de página leve e assíncrono usando JavaScript vanilla, GSAP e Vite.

Importância das Transições de Página

As transições de página são essenciais para criar uma experiência de usuário agradável. Elas permitem que os usuários naveguem entre diferentes páginas do aplicativo sem sentir uma interrupção na experiência. Além disso, as transições de página podem ser usadas para criar uma sensação de profundidade e dimensão, tornando o aplicativo mais interessante e atraente.

Desafios de Implementar Transições de Página

Implementar transições de página pode ser um desafio, pois requer uma combinação de habilidades técnicas e criativas. É necessário considerar fatores como a velocidade da transição, a aparência da transição e a compatibilidade com diferentes dispositivos e navegadores. Além disso, é necessário garantir que a transição de página seja levemente e assíncrona, para evitar atrasos e melhorar a experiência do usuário.

Arquitetura do Sistema de Transição de Página

O sistema de transição de página que vamos criar utilizará a seguinte arquitetura:

* JavaScript vanilla para a lógica de negócios
* GSAP para as animações e transições
* Vite para a configuração e gerenciamento do projeto

Essa arquitetura permitirá que criemos um sistema de transição de página leve e assíncrono, que seja fácil de configurar e gerenciar.

Implementação do Sistema de Transição de Página

A implementação do sistema de transição de página será realizada em várias etapas:

1. Criação da estrutura básica do sistema
2. Implementação das animações e transições com GSAP
3. Configuração da lógica de negócios com JavaScript vanilla
4. Testes e depuração do sistema

Essas etapas permitirão que criemos um sistema de transição de página robusto e eficaz, que atenda às necessidades dos usuários e dos desenvolvedores.

Conclusão

As transições de página são uma parte fundamental da experiência do usuário, e criar um sistema de transição de página leve e assíncrono pode melhorar a usabilidade e a aparência do aplicativo. Neste artigo, vamos explorar como criar um sistema de transição de página usando JavaScript vanilla, GSAP e Vite, e implementar as animações e transições com GSAP.

Configuração do Projeto

Criação do Projeto com Vite

npm create vite@latest

Estrutura de Pastas


yourproject/
├── node_modules/
├── public/
├── src/
│ ├── main.js
│ └── style.css
├── gitignore
├── index.html
├── package-lock.json
└── package.json

Configuração Básica do HTML e CSS


<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Building Async Page Transitions in Vanilla JavaScript</title>
</head>
<body>
<div data-transition="wrapper">
<div data-transition="container" data-namespace="home">
<main id="page_content" class="page_content"></main>
</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>

@font-face {
font-family: "Neue";
src: url("/NeueMontreal-Medium.ttf");
font-weight: 600;
font-style: normal;
font-display: swap;
}

:root {
font-family: Neue;
line-height: 1;
color: rgb(0, 0, 0);
background-color: #000000;
}

*,
*::before,
*::after {
box-sizing: border-box;
}

body {
font-family: Neue;
margin: 0;
display: flex;
overflow-x: hidden;
min-height: 100vh;
}

main {
width: 100vw;
}

h1 {
font-size: 28.2vw;
margin: 0;
line-height: 80%;
}

a {
color: black;
text-decoration: none;
text-transform: uppercase;
}

.hero {
background-color: white;
width: 100%;
height: 100vh;
overflow: hidden;
display: flex;
justify-content: space-between;
flex-direction: column;
padding: 20px;
align-items: center;
}

.hero_content {
width: 100%;
padding-top: 8vh;
text-align: center;
}

[data-transition="container"] {
transform: translateZ(0);
backface-visibility: hidden;
}

Implementação do Roteador

Definição de Rotas


const routes = {
  "/": {
    namespace: "home",
    loader: () => import("./pages/home/home.js"),
  },
  "/alternative-page": {
    namespace: "alternative-page",
    loader: () => import("./pages/alternative-page/alternative-page.js"),
  },
};

Class Roteador


class Router {
  constructor() {
    this.currentNamespace = null;
    this.isTransitioning = false;
  }

  async loadInitialPage() {
    const path = window.location.pathname;
    const route = routes[path];
    const pageModule = await route.loader();
    const content = document.getElementById("page_content");
    content.innerHTML = pageModule.default();
    const container = document.querySelector('[data-transition="container"]');
    container.setAttribute("data-namespace", route.namespace);
    this.currentNamespace = route.namespace;
  }

  async navigate(path) {
    if (this.isTransitioning || window.location.pathname === path) return;
    window.history.pushState({}, "", path);
    await this.performTransition(path);
  }

  async performTransition(path) {
    if (this.isTransitioning) return;
    this.isTransitioning = true;
    try {
      const route = routes[path];
      if (!route || this.currentNamespace === route.namespace) return;
      const pageModule = await route.loader();
      await executeTransition({
        nextHTML: pageModule.default(),
      });
      this.currentNamespace = route.namespace;
    } finally {
      this.isTransitioning = false;
    }
  }
}

Instância do Roteador


export const router = new Router();

Motor de Transição

Para criar o motor de transição, precisamos implementar a lógica de transição assíncrona. Isso envolve criar um segundo container, injetar o conteúdo do próximo página nele, executar a animação entre os dois containers e, finalmente, limpar o ambiente.

Criando o Motor de Transição


import { gsap } from "../lib/index.js";
import { defaultTransition } from "./animations/defaultTransition.js";

export async function executeTransition({ nextHTML }) {
  const currentContainer = document.querySelector('[data-transition="container"]');
  const wrapper = document.querySelector('[data-transition="wrapper"]');

  // Clonar o container para o próximo página
  const nextContainer = currentContainer.cloneNode(false);
  const content = document.createElement("main");
  content.id = "page_content";
  content.className = "page_content";
  content.innerHTML = nextHTML;
  nextContainer.appendChild(content);

  // Adicionar o próximo página ao DOM
  wrapper.appendChild(nextContainer);

  // Executar a animação de transição
  const timeline = defaultTransition(currentContainer, nextContainer);
  await timeline.then();

  // Limpar o ambiente
  currentContainer.remove();
  gsap.set(nextContainer, { clearProps: "all" });
  gsap.set(nextContainer, { force3D: true });
}

Para implementar a lógica de transição assíncrona, precisamos criar uma função chamada `performTransition`. Essa função será responsável por executar a transição entre as páginas.





async performTransition(path) {
  // Bloquear a execução se uma transição estiver em andamento
  if (this.isTransitioning) return;
  this.isTransitioning = true;

  try {
    // Resolver a rota correspondente
    const route = routes[path];

    // Executar a transição assíncrona
    await executeTransition({
      nextHTML: pageModule.default(),
    });

    // Atualizar o namespace atual
    this.currentNamespace = route.namespace;
  } finally {
    // Liberar o bloqueio de transição
    this.isTransitioning = false;
  }
}

Agora que temos a lógica de transição assíncrona implementada, podemos atualizar a função `navigate` para usar a `performTransition` em vez de executar a transição diretamente.


async navigate(path) {
  if (window.location.pathname === path || this.isTransitioning) return;
  window.history.pushState({}, "", path);
  await this.performTransition(path);
}

Com a lógica de transição assíncrona implementada, podemos agora adicionar uma animação de entrada para dar mais profundidade à transição.

Adicionando Animação de Entrada


import { gsap } from "../lib/index.js";
const ENTER = (nextContainer, delay) => {
  const t = nextContainer?.querySelector("h1");
  if (!t) return null;
  gsap.set(t, { y: "100%" });
  const tl = gsap.timeline({
    delay,
  });
  tl.to(t, {
    y: 0,
    duration: 1.2,
    force3D: true,
    ease: "expo.out",
  }, 0);
  return { timeline: tl };
};
export default ENTER;

Para adicionar a animação de entrada, precisamos chamar a função `ENTER` dentro da função `init` de cada página.


export function init({ container }) {
  ENTER(container, 0.45);
}

Agora que temos a animação de entrada adicionada, podemos atualizar a função `executeTransition` para chamar a função `init` do próximo página.


export async function executeTransition({ nextHTML, nextModule }) {
  // ...

  if (nextModule?.init) {
    nextModule.init({ container: nextContainer });
  }

  // ...
}

Integração e Funcionamento

O roteador e o motor de transição se integram para fornecer uma experiência de usuário suave e atraente. O roteador é responsável por gerenciar a navegação entre as páginas, enquanto o motor de transição é responsável por criar as transições animadas entre as páginas.

Como funciona o sistema de transição de página

O sistema de transição de página funciona da seguinte maneira:

1. O roteador intercepta as requisições de navegação e atualiza a URL do navegador.
2. O motor de transição é chamado para criar a transição animada entre as páginas.
3. O motor de transição cria uma cópia da página atual e injeta a página nova na cópia.
4. O motor de transição anima a transição entre as duas páginas, criando uma transição suave e atraente.
5. Após a transição ser concluída, o motor de transição remove a página anterior e atualiza a página atual.

Código fonte


// Em router.js
async performTransition(path) {
  // ...
  await executeTransition({
    nextHTML: pageModule.default(),
  });
  // ...
}

// Em pageTransition.js
export async function executeTransition({ nextHTML }) {
  const currentContainer = document.querySelector('[data-transition="container"]');
  const wrapper = document.querySelector('[data-transition="wrapper"]');
  // ...
  const timeline = defaultTransition(currentContainer, nextContainer);
  await timeline.then();
  // ...
}

Integração com o roteador

O motor de transição é chamado pelo roteador para criar as transições animadas entre as páginas. O roteador atualiza a URL do navegador e chama o motor de transição para criar a transição animada.


// Em router.js
async navigate(path) {
  // ...
  await this.performTransition(path);
  // ...
}

Integração com o motor de transição

O motor de transição é responsável por criar as transições animadas entre as páginas. Ele cria uma cópia da página atual e injeta a página nova na cópia, e então anima a transição entre as duas páginas.


// Em pageTransition.js
export async function executeTransition({ nextHTML }) {
  // ...
  const timeline = defaultTransition(currentContainer, nextContainer);
  await timeline.then();
  // ...
}

Fonte de Referência: tympanus.net.
Curadoria e Adaptação: Redação Yassutaro Developers.



Redação YTI&W-News

Redação Developers | Yassutaro TI & Web

Notícias do universo do Desenvolvimento Web, dicas e tutoriais para Webmasters.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Publicado em:Desenvolvimento Web
Fale Conosco
×

Inscreva-se em nossa Newsletter!


Receba nossos lançamentos e artigos em primera mão!