Vue.js: Vue Router

Última atualização: 2026-10-20

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


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):

4 perguntas:

(2) Solução com o Vue Router 4: 5 rotas + 5 componentes

JS
// 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

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:


3. Inicialização da rota

(1) Código de inicialização completo

JS
// 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

(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

JS
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)

JS
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') 
  }
]
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

JS
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')
      }
    ]
  }
]

(4) Roteamento nomeado

JS
const routes = [
  { 
    path: '/products/:id', 
    name: 'product-detail',  // Named Routing
    component: () => import('@/views/ProductDetailPage.vue') 
  }
]
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

JS
const routes = [
  { path: '/', component: () => import('@/views/HomePage.vue') },
  // ... Other Routes
  {
    path: '/:pathMatch(.*)*',  // Match all undefined routes
    component: () => import('@/views/NotFoundPage.vue')
  }
]

▶ Exemplo: 5 tipos de configurações de roteamento

JS
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') }
]
▶ Experimente

Saída:

TEXT
/ abre HomePage; /products/42 abre o detalhe com route.params.id = 42.
/admin/products renderiza o filho dentro do AdminLayout (router-view aninhado).
Qualquer caminho inexistente cai em NotFoundPage pela rota curinga.

▶ Exemplo: Carregamento diferido de rotas (carregamento sob demanda de 5 componentes)

JS
const routes = [
  // ✅ Recommendations:News import
  { path: '/', component: () => import('@/views/HomePage.vue') },
  { path: '/products', component: () => import('@/views/ProductsPage.vue') }
]
▶ Experimente

Saída:

TEXT
Cada rota vira um arquivo JS separado no build.
A primeira tela baixa só o chunk da HomePage.
Ao visitar /products, o chunk ProductsPage é baixado naquele momento.

5. 5 Tipos de navegação

(2) Navegação programática (router.push)

JS
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

▶ Exemplo: 5 Tipos de navegação

VUE
<!-- 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>
▶ Experimente
JS
import { useRouter } from 'vue-router'
const router = useRouter()
function goToProduct(id) {
  router.push({ name: 'product-detail', params: { id } })
}

Saída:

TEXT
Clicar em Products leva a /products; a versão com name usa a rota nomeada.
O link com params gera /product/123 e o de query gera /search?q=vue.
O botão dispara router.push e o histórico registra a nova entrada.

6. Route Guard (Navigation Guard)

(1) 3 tipos de guardas

JS
// 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

JS
// 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', 
      query: { 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()
})
▶ Experimente
JS
// Routing meta Layout
const routes = [
  {
    path: '/dashboard',
    component: () => import('@/views/DashboardPage.vue'),
    meta: { requiresAuth: true }  // You must log in
  }
]

7. Exercício abrangente: guarda de navegação de login

▶ Exemplo: Completar o Login Guard

JS
router.beforeEach((to, from, next) => {
  const token = localStorage.getItem('token')
  const isLoggedIn = !!token
  
  if (to.meta.requiresAuth && !isLoggedIn) {
    return next({ name: 'login', query: { redirect: to.fullPath } })
  }
  
  if (to.name === 'login' && isLoggedIn) {
    return next({ name: 'home' })
  }
  
  next()
})
▶ Experimente

Saída:

TEXT
Sem token, acessar /admin redireciona para /login?redirect=/admin.
Depois do login, o usuário volta para a rota original.
Já logado, acessar /login leva direto para a home.

(1) 📊 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(.*)*'

(2) 📊 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, createWebHistory ou createWebHashHistory?
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.push e router.replace?
R push adiciona a página ao histórico do navegador (permitindo que os usuários voltem), enquanto replace substitui a página atual (sem deixar rastros no histórico). Use replace apó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 use to.meta.requiresAuth no guarda. Eles são usados para permissões, títulos, trilhas de navegação e muito mais.

📖 Resumo


📝 Exercícios

  1. 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
  2. Problemas avançados (Dificuldade: ⭐⭐)

    Implementação do roteamento de produtos no comércio eletrônico:

    • /products Página de lista
    • /products/:id Página de detalhes (parâmetros dinâmicos)
    • /products/:id/edit Editar página
    • Tratamento do erro 404
  3. Problema desafiador (Dificuldade: ⭐⭐⭐)

    Implementar um sistema completo de roteamento de back-end para comércio eletrônico:

    1. Mais de 10 páginas (página inicial/produtos/pedidos/usuários/configurações/login/404 etc.)
    2. Rotas aninhadas (/admin/dashboard, /admin/products etc.)
    3. Carregamento diferido de rotas (carregamento mais rápido da primeira tela)
    4. Faça login como guarda (se ainda não estiver conectado, acesse /login; se já estiver conectado, volte a esta página)
    5. Abordagem abrangente de 5 métodos de navegação
    6. Navegação programática (Clique no botão para navegar)
    7. Configuração de rotas com tipagem forte no TypeScript
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%