Vue Router — Roteamento Client-Side
Quando você usa o Gmail, clica em “Enviados” e a lista muda sem a página piscar. Quando você navega pelo Spotify, a música continua tocando enquanto você vai para outra tela. Nos dois casos, o navegador não está recarregando a página — o JavaScript está trocando o conteúdo exibido sem sair do mesmo HTML. Isso é roteamento client-side: a URL muda, o conteúdo muda, mas a aplicação permanece viva na memória.
O Vue Router é a biblioteca oficial para fazer isso em aplicações Vue 3. Ele mapeia URLs a componentes e gerencia a navegação sem recarregamento.
1. MPA vs SPA — o que muda na navegação
Numa aplicação tradicional (MPA — Multi Page Application), cada URL é um arquivo HTML diferente no servidor. Clicar num link faz o navegador carregar uma página nova do zero — perde-se o estado em memória, a música para, o carrinho some.
Numa SPA com Vue Router, existe apenas um arquivo HTML. O router intercepta a navegação, atualiza a URL no navegador e troca o componente renderizado — sem sair da aplicação.
O problema concreto:
<!-- ❌ link tradicional — recarrega a página, destrói o estado Vue -->
<a href="/sobre">Sobre</a>
<!-- ✅ RouterLink — navega sem reload, mantém a aplicação viva -->
<RouterLink to="/sobre">Sobre</RouterLink>
Usar <a href> numa SPA é como ligar o carro, ir até o destino e apagar o motor — na próxima vez, você precisa religar tudo do zero.
2. Instalando e configurando o Vue Router
Instalação
npm install vue-router
Criando o arquivo de rotas
Por convenção, as rotas ficam em src/router/index.js.
// src/router/index.js
import { createRouter, createWebHistory } from "vue-router";
import HomeView from "../views/HomeView.vue";
import PlaylistView from "../views/PlaylistView.vue";
const routes = [
{ path: "/", component: HomeView },
{ path: "/playlists/nova", component: PlaylistView },
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
createRoutercria a instância do routercreateWebHistoryusa a History API do navegador — URLs limpas, sem#routesé um array que mapeia cada URL a um componente
Registrando no main.js
// src/main.js
import { createApp } from "vue";
import App from "./App.vue";
import router from "./router";
const app = createApp(App);
app.use(router); // registra o plugin
app.mount("#app");
app.use(router)precisa vir antes deapp.mount. Sem isso,<RouterView>e<RouterLink>não existem nos templates.
3. <RouterView> e <RouterLink>
Com o router configurado, o App.vue deixa de conter o conteúdo da aplicação diretamente. Ele passa a ser a “casca” — com navegação e o espaço onde cada view é renderizada.
<!-- App.vue -->
<template>
<nav>
<RouterLink to="/">Início</RouterLink>
<RouterLink to="/playlists/nova">Nova Playlist</RouterLink>
</nav>
<RouterView />
</template>
<RouterView />é o “buraco” onde o componente da rota ativa é renderizado<RouterLink to="...">gera um<a>que navega sem recarregar a página
O Vue Router adiciona automaticamente a classe router-link-active no link da rota atual — útil para estilizar o item ativo na nav.
4. Views — organizando as telas
Por convenção, os componentes que representam telas completas ficam em src/views/. São componentes Vue normais — a diferença é só organizacional.
Cada view é responsável por buscar seus próprios dados. Não faz sentido buscar tudo no App.vue e passar para baixo via props — isso quebra o encapsulamento e faz o App.vue saber de tudo.
<!-- src/views/HomeView.vue -->
<template>
<ul>
<li v-for="musica in musicas" :key="musica.id">{{ musica.titulo }}</li>
</ul>
</template>
<script setup>
import { ref, onMounted } from "vue";
const musicas = ref([]);
onMounted(async () => {
const res = await fetch("https://api.exemplo.com/musicas");
musicas.value = await res.json(); // cada view cuida dos próprios dados
});
</script>
Quando o usuário navega para
/, o Vue montaHomeViewe dispara oonMounted— os dados são buscados nesse momento, não antes.
5. Navegação programática — useRouter()
Às vezes precisamos navegar por código — após salvar um formulário, por exemplo. Para isso, usamos useRouter().
<script setup>
import { useRouter } from "vue-router";
const router = useRouter();
async function salvar(produto) {
await fetch("https://api.exemplo.com/products", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(produto),
});
router.push("/"); // redireciona para a home após salvar
}
</script>
useRouter()retorna a instância do routerrouter.push('/destino')navega para a rota indicada — equivale ao usuário clicar num<RouterLink>
Sem o
router.push, o usuário ficaria na tela do formulário depois de salvar, sem feedback visual de que a operação foi concluída.
6. Parâmetros de rota — useRoute()
Quando precisamos de uma rota dinâmica — como a página de detalhe de um item — usamos :id na definição da rota.
// src/router/index.js
{ path: "/products/:id", component: ProdutoDetalheView }
Para ler o valor do parâmetro na view, usamos useRoute():
<script setup>
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
const route = useRoute();
const produto = ref(null);
onMounted(async () => {
const id = route.params.id; // lê o :id da URL atual
const res = await fetch(`https://api.exemplo.com/products/${id}`);
produto.value = await res.json();
});
</script>
useRoute()dá acesso à rota atual.useRouter()dá acesso ao router para navegar. São funções diferentes.
7. Fetch com DELETE
O método DELETE remove um recurso no servidor. Não precisa de body — o id vai na URL.
async function remover(id) {
const res = await fetch(`https://api.exemplo.com/products/${id}`, {
method: "DELETE",
});
if (!res.ok) throw new Error("Erro ao remover");
// após confirmar o DELETE no servidor, atualizar o estado local
itens.value = itens.value.filter((item) => item.id !== id);
}
Por que usar .filter() em vez de fazer um novo GET após o DELETE?
- O servidor confirmou a remoção — não precisamos perguntar de novo o que ele tem
- Um GET extra é uma requisição desnecessária que aumenta latência
.filter()cria um novo array sem o item removido e o Vue atualiza a tela imediatamente
filternão modifica o array original — retorna um novo array. Por isso atribuímos o resultado de volta aitens.value.
Referência rápida
| Recurso | Para que serve |
|---|---|
npm install vue-router | Instalar a biblioteca |
createRouter({ history, routes }) | Criar a instância do router |
createWebHistory() | URLs limpas sem # |
app.use(router) | Registrar o router na aplicação |
<RouterView /> | Onde a view da rota atual é renderizada |
<RouterLink to="..."> | Navegar sem recarregar a página |
useRouter() | Acessar o router para navegar por código |
router.push('/rota') | Navegar programaticamente |
useRoute() | Acessar dados da rota atual (params, query) |
route.params.id | Ler parâmetro dinâmico da URL |
fetch(url, { method: 'DELETE' }) | Remover recurso no servidor |
.filter() | Remover item do array local após DELETE |