Vue.js: Vue Router
Última atualização: 2026-08-26
O Vue Router é o gerenciador de roteamento oficial do Vue — ele permite que sua SPA (aplicação de página única) tenha várias “páginas”, sendo que cada URL corresponde a um componente. O Vue Router 4 é a versão projetada para o Vue 3 e oferece suporte total à API de Composição.
No cerne do roteamento do SPA está o mapeamento entre URL e componentes. Dominar o Vue Router 4 é uma habilidade essencial para desenvolver qualquer aplicativo Vue que não seja trivial.
1. O que você vai aprender
- Inicialização do createRouter + createWebHistory
- 5 tipos de rotas: estáticas, dinâmicas, aninhadas, nomeadas e com curinga
- Navegação programática (router.push / replace / go)
- Carregamento diferido de rotas (importação dinâmica)
- Parâmetros de rota (params / consulta)
- Guarda-rotas (beforeEach / beforeEnter)
- 5 cenários-chave do mundo real
2. O “pesadelo do 404” de um aplicativo de página única
(1) Problema: 5 páginas, 5 casos de código duplicado
O painel de administração da Alice tinha 5 páginas (Página inicial/Produtos/Pedidos/Usuários/Configurações):
<!-- ❌ The "Broken" Version: Use v-if to switch 5 components -->
<template>
<div>
<button @click="currentPage = 'home'">Home</button>
<button @click="currentPage = 'products'">Products</button>
<button @click="currentPage = 'orders'">Orders</button>
<div v-if="currentPage === 'home'"><HomePage /></div>
<div v-else-if="currentPage === 'products'"><ProductsPage /></div>
<div v-else-if="currentPage === 'orders'"><OrdersPage /></div>
<div v-else>Page not found</div>
</div>
</template>
4 perguntas:
- A URL permanece inalterada: ao atualizar a página, a página atual é perdida
- Sem link para compartilhamento: Não é possível copiar a URL para compartilhar com colegas
- Ausência dos botões “Avançar” e “Voltar” do navegador: Experiência do usuário insatisfatória
- SEO inadequado: os mecanismos de busca não conseguem interpretá-lo
(2) Solução com o Vue Router 4: 5 rotas + 5 componentes
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [
{ path: '/', component: () => import('@/views/HomePage.vue') },
{ path: '/products', component: () => import('@/views/ProductsPage.vue') },
{ path: '/orders', component: () => import('@/views/OrdersPage.vue') },
{ path: '/users', component: () => import('@/views/UsersPage.vue') },
{ path: '/settings', component: () => import('@/views/SettingsPage.vue') }
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
<!-- App.vue -->
<template>
<nav>
<router-link to="/">Home</router-link>
<router-link to="/products">Products</router-link>
<router-link to="/orders">Orders</router-link>
</nav>
<!-- ✅ Key:router-view Render the component for the current route -->
<router-view />
</template>
5 rotas + 1 visualização do roteador = um SPA completo. As URLs são sincronizadas automaticamente, e os botões “Avançar” e “Voltar” do navegador funcionam como esperado.
(3) Receita
Depois de usar o Vue Router:
- Sincronização de URL: Sincronização automática; atualiza os dados sem perder os já existentes
- Compartilhável: Cada página tem uma URL
- Histórico do navegador: os botões “Avançar” e “Voltar” funcionam conforme o esperado
- Otimizado para SEO: suporte a SSR (Nuxt 3)
- Volume de código: 5 diretivas v-if → 5 linhas na matriz de rotas (-80%)
3. Inicialização da rota
(1) Código de inicialização completo
// src/router/index.js
import { createRouter, createWebHistory, createWebHashHistory } from 'vue-router'
// 1. Define Routes(Lazy Loading)
const routes = [
{ path: '/', component: () => import('@/views/HomePage.vue') },
{ path: '/products', component: () => import('@/views/ProductsPage.vue') }
]
// 2. Create router Examples
const router = createRouter({
// history Mode: URL without # (Recommended)
history: createWebHistory(),
// hash Mode: URL with # (Compatibility with older browsers)
// history: createWebHashHistory(),
routes,
// Scrolling Behavior:Scroll to the top when switching routes
scrollBehavior(to, from, savedPosition) {
return savedPosition || { top: 0 }
}
})
export default router
(2) Registrando o arquivo 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) // Registration Routes
app.mount('#app')
(3) Comparação dos dois principais modelos históricos
| Aspecto | createWebHistory | createWebHashHistory |
|---|---|---|
| Formato da URL | /products |
/#/products |
| SEO | ✅ Otimizado para SEO | ❌ Não otimizado para SEO |
| Configuração do servidor | Obrigatório (try_files) | Não obrigatório |
| Compatibilidade com navegadores | IE10+ | IE8+ |
| Avaliação | ⭐⭐⭐⭐⭐ | ⭐⭐ |
4. 5 tipos de configurações de roteamento
(1) Roteamento estático
const routes = [
{ path: '/', component: () => import('@/views/HomePage.vue') },
{ path: '/about', component: () => import('@/views/AboutPage.vue') },
{ path: '/contact', component: () => import('@/views/ContactPage.vue') }
]
(2) Roteamento dinâmico (parâmetros)
const routes = [
// /products/123
{
path: '/products/:id',
component: () => import('@/views/ProductDetailPage.vue')
},
// /users/456/posts/789
{
path: '/users/:userId/posts/:postId',
component: () => import('@/views/PostPage.vue')
},
// Optional Parameters
{
path: '/news/:category?',
component: () => import('@/views/NewsPage.vue')
}
]
<!-- ProductDetailPage.vue Receive Parameters -->
<script setup>
import { useRoute } from 'vue-router'
const route = useRoute()
console.log(route.params.id) // '123'
</script>
(3) Rotas aninhadas
const routes = [
{
path: '/users',
component: () => import('@/views/UsersPage.vue'),
children: [
{
path: '', // Default Subroute
component: () => import('@/views/UsersListPage.vue')
},
{
path: ':id', // /users/123
component: () => import('@/views/UserDetailPage.vue')
}
]
}
]
<!-- UsersPage.vue -->
<template>
<div>
<h1>Users</h1>
<router-view /> <!-- Subnet Route Outbound -->
</div>
</template>
(4) Roteamento nomeado
const routes = [
{
path: '/products/:id',
name: 'product-detail', // Named Routing
component: () => import('@/views/ProductDetailPage.vue')
}
]
<!-- Navigate via name, Avoid hard-coding URL -->
<router-link :to="{ name: 'product-detail', params: { id: 123 } }">
Product 123
</router-link>
(5) Erro 404 de curinga
const routes = [
{ path: '/', component: () => import('@/views/HomePage.vue') },
// ... Other Routes
{
path: '/:pathMatch(.*)*', // Match all undefined routes
component: () => import('@/views/NotFoundPage.vue')
}
]
5. 5 Tipos de navegação
(1) Navegação declarativa (router-link)
<template>
<!-- String Path -->
<router-link to="/products">Products</router-link>
<!-- Named Routing(Recommendations) -->
<router-link :to="{ name: 'products' }">Products</router-link>
<!-- Dynamic Parameters -->
<router-link :to="{ name: 'product-detail', params: { id: 123 } }">
Product 123
</router-link>
<!-- Query Parameters -->
<router-link :to="{ path: '/search', クエリ: { q: 'vue' } }">
Search
</router-link>
</template>
(2) Navegação programática (router.push)
import { useRouter } from 'vue-router'
const router = useRouter()
function goToProduct(id) {
router.push(`/products/${id}`) // String
// or
router.push({ name: 'product-detail', params: { id } }) // Object
}
function goBack() {
router.back() // Back
}
function goForward() {
router.forward() // Forward
}
function replaceCurrent() {
router.replace('/login') // Replace(Leaving No Trace of History)
}
(3) 5 diferenças entre “push” e “replace”
| Método | Comportamento | Histórico |
|---|---|---|
router.push() |
Ir para uma nova página | Salvar esta página (é possível voltar) |
router.replace() |
Substituir a página atual | Não deixar rastros (não é possível voltar) |
router.go(n) |
Avançar/retroceder n passos | Ver histórico |
router.back() |
Dê um passo atrás | Explore a história |
router.forward() |
Dê um passo à frente | Percorra a história |
(4) Comparação entre programação procedural e declarativa
| Cenário | Recomendação |
|---|---|
| O usuário clica no link | router-link (declarativo) |
| Navegação acionada por JS | router.push (programaticamente) |
| Redirecionar após o envio do formulário | router.push |
| Redirecionar após o login | router.replace |
| Redirecionamento automático 404 | router.back |
6. Route Guard (Navigation Guard)
(1) 3 tipos de guardas
// 1. Global Frontline Guard(Most Commonly Used)
router.beforeEach((to, from, next) => {
const isLoggedIn = !!localStorage.getItem('token')
if (to.meta.requiresAuth && !isLoggedIn) {
next('/login') // Skip Login
} else {
next() // Clearance
}
})
// 2. Dedicated Route Guard
const routes = [
{
path: '/admin',
component: () => import('@/views/AdminPage.vue'),
beforeEnter: (to, from, next) => {
if (isAdmin()) next()
else next('/403')
}
}
]
// 3. In-Component Guard
// Within the component:beforeRouteEnter / beforeRouteUpdate / beforeRouteLeave
(2) Exemplo completo de proteção de login
// router/index.js
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token')
const isLoggedIn = !!token
// Pages that require login
if (to.meta.requiresAuth && !isLoggedIn) {
return next({
name: 'login',
クエリ: { redirect: to.fullPath } // Redirect after logging in
})
}
// Already logged in. Go to the login page.
if (to.name === 'login' && isLoggedIn) {
return next({ name: 'home' })
}
next()
})
// Routing meta Layout
const routes = [
{
path: '/dashboard',
component: () => import('@/views/DashboardPage.vue'),
meta: { requiresAuth: true } // You must log in
}
]
7. Exemplo completo: Sistema de roteamento de back-end para comércio eletrônico
▶ Exemplo: 1. 5 tipos de configurações de roteamento
const routes = [
// 1. Static Routing
{ path: '/', name: 'home', component: () => import('@/views/HomePage.vue') },
// 2. Dynamic Routing
{
path: '/products/:id',
name: 'product-detail',
component: () => import('@/views/ProductDetailPage.vue')
},
// 3. Nested Routes
{
path: '/admin',
component: () => import('@/views/AdminLayout.vue'),
meta: { requiresAuth: true },
children: [
{ path: '', name: 'admin-dashboard', component: () => import('@/views/DashboardPage.vue') },
{ path: 'products', name: 'admin-products', component: () => import('@/views/AdminProductsPage.vue') },
{ path: 'orders', name: 'admin-orders', component: () => import('@/views/AdminOrdersPage.vue') }
]
},
// 4. Named Routing
{
path: '/user/:userId',
name: 'user-profile',
component: () => import('@/views/UserProfilePage.vue')
},
// 5. 404
{ path: '/:pathMatch(.*)*', name: 'not-found', component: () => import('@/views/NotFoundPage.vue') }
]
▶ Exemplo: 2. Carregamento diferido de rotas (carregamento sob demanda de 5 componentes)
const routes = [
// ✅ Recommendations:News import
{ path: '/', component: () => import('@/views/HomePage.vue') },
{ path: '/products', component: () => import('@/views/ProductsPage.vue') }
]
▶ Exemplo: 3. 5 Tipos de navegação
<!-- 1. String Path -->
<router-link to="/products">Products</router-link>
<!-- 2. Named Routing(Recommendations)-->
<router-link :to="{ name: 'products' }">Products</router-link>
<!-- 3. Dynamic Parameters -->
<router-link :to="{ name: 'product-detail', params: { id: 123 } }">
Product 123
</router-link>
<!-- 4. Query Parameters -->
<router-link :to="{ path: '/search', query: { q: 'vue' } }">
Search
</router-link>
<!-- 5. Programmatic Navigation -->
<button @click="goToProduct(123)">Go to Product</button>
import { useRouter } from 'vue-router'
const router = useRouter()
function goToProduct(id) {
router.push({ name: 'product-detail', params: { id } })
}
▶ Exemplo: 4. Completar o Login Guard
router.beforeEach((to, from, next) => {
const token = localStorage.getItem('token')
const isLoggedIn = !!token
if (to.meta.requiresAuth && !isLoggedIn) {
return next({ name: 'login', クエリ: { redirect: to.fullPath } })
}
if (to.name === 'login' && isLoggedIn) {
return next({ name: 'home' })
}
next()
})
▶ Exemplo: 5. Referência rápida para 5 erros comuns
| Erro | Sintoma | Solução |
|---|---|---|
| falta a visualização do roteador | Página não exibida | Adicionar <router-view /> |
| As rotas não são carregadas de forma diferida | Carregamento lento da primeira tela | Use () => import() para importação dinâmica |
| Loop infinito | Não é possível sair | Impedir que o next() acione o beforeEach novamente |
| Roteamento aninhado sem saída | Subpágina não exibida | Adicionar <router-view /> ao componente pai |
| 404 Rota não encontrada | Erro | Adicionar path: '/:pathMatch(.*)*' |
▶ Exemplo: 6. 5 Principais comparações de desempenho
| Modo | Primeira tela | Botão | Aplicável |
|---|---|---|---|
| Importação estática | Lenta | Rápida | Projetos pequenos |
| Importação dinâmica | ⭐⭐⭐⭐⭐ | Lenta no primeiro carregamento | Recomendado |
| Carregamento diferido de grupos de roteamento | ⭐⭐⭐⭐⭐ | Lento no primeiro carregamento | Projetos grandes |
| pré-busca | ⭐⭐⭐⭐ | Rápido | Prioridade à experiência do usuário |
| SSR | ⭐⭐⭐⭐⭐ | Rápido | Nuxt 3 |
❓ Perguntas Frequentes
P: O que devo escolher,
createWebHistoryoucreateWebHashHistory? R:createWebHistory(URLs sem#, otimizadas para SEO) requer configuração do servidor;createWebHashHistory(URLs com#) é compatível com navegadores mais antigos.createWebHistoryé recomendado para ambientes de produção.
P: Como o roteamento dinâmico recebe parâmetros? R: Use o gancho
useRoute():const route = useRoute(); route.params.id.
P: Qual é a diferença entre
router.pusherouter.replace? R:pushadiciona a página ao histórico do navegador (permitindo que os usuários voltem), enquantoreplacesubstitui a página atual (sem deixar rastros no histórico). Usereplaceapós o login (já que os usuários não podem voltar à página de login).
P: O router guard pode ser executado de forma assíncrona? R: Sim.
beforeEach(async (to, from, next) => { await checkAuth(); next() }). Mas tome cuidado para evitar loops infinitos.
P: Como se implementa o roteamento aninhado? R: Configure a rota filha na rota pai usando
children: []e adicione<router-view />ao modelo do componente pai como ponto de saída para a rota filha.
P: Quais são as diferenças entre o Vue Router 4 e o Vue Router 3? R: O Vue Router 4 é compatível com a Composition API (useRouter/useRoute), oferece uma inferência de tipos mais robusta no TypeScript e alterou os parâmetros do navigation guard (to/from/next). Os projetos do Vue 3 devem usar o Vue Router 4.
P: Em que medida o carregamento diferido melhora o desempenho? R: Ele pode reduzir o tempo de carregamento da primeira tela em 50 a 80% (ao não carregar páginas que ainda não foram visitadas). O efeito é particularmente perceptível em projetos grandes (mais de 10 páginas).
P: Como faço para usar os metacampos nos guardas de rota? R: Adicione
meta: { requiresAuth: true }à configuração da rota e useto.meta.requiresAuthno guarda. Eles são usados para permissões, títulos, trilhas de navegação e muito mais.
📖 Resumo
- O Vue Router 4 é o gerenciador de roteamento oficial do Vue 3
- 5 tipos de rotas: estáticas, dinâmicas, aninhadas, nomeadas e com curinga
- 5 tipos de navegação: router-link, router.push, replace, back, forward
- 3 tipos de observadores: global (beforeEach), específico da rota (beforeEnter) e interno ao componente
- O carregamento diferido de rotas (importações dinâmicas) reduz o tempo até a primeira visualização
- Recomenda-se usar
createWebHistory;createWebHashHistoryserve para garantir a compatibilidade com navegadores mais antigos - Rotas aninhadas com filhos +
<router-view />
📝 Exercícios
-
Questões básicas (Dificuldade: ⭐)
Implementar uma SPA simples com várias páginas:
- 3 páginas: Página inicial / Sobre nós / Contato
- Navegação superior + visualização do router na parte inferior
- Configure o roteador usando
vue-router
-
Problemas avançados (Dificuldade: ⭐⭐)
Implementação do roteamento de produtos no comércio eletrônico:
/productsPágina de lista/products/:idPágina de detalhes (parâmetros dinâmicos)/products/:id/editEditar página- Tratamento do erro 404
-
Problema desafiador (Dificuldade: ⭐⭐⭐)
Implementar um sistema completo de roteamento de back-end para comércio eletrônico:
- Mais de 10 páginas (página inicial/produtos/pedidos/usuários/configurações/login/404 etc.)
- Rotas aninhadas (/admin/dashboard, /admin/products etc.)
- Carregamento diferido de rotas (carregamento mais rápido da primeira tela)
- Faça login como guarda (se ainda não estiver conectado, acesse /login; se já estiver conectado, volte a esta página)
- Abordagem abrangente de 5 métodos de navegação
- Navegação programática (Clique no botão para navegar)
- Configuração de rotas com tipagem forte no TypeScript