Nuxt: Páginas e Rotas

Última atualização: 2026-08-26

Ao adicionar páginas de detalhes de produtos à MegaShop, Bob configurou manualmente 50 rotas vue-router. Toda vez que um novo produto era listado, ele tinha que editar os arquivos de rota—era uma dor de cabeça. Charlie disse a ele que o Nuxt 3 gera rotas automaticamente com base em convenções de arquivos, então criar um arquivo é o mesmo que criar uma rota.

1. O Que Você Vai Aprender


2. Uma História Real de um Administrador

(1) Dor: O Pesadelo da Configuração Manual de Rotas

Bob configurou 1.000 rotas para a MegaShop usando o Vue Router tradicional—uma para cada categoria e cada página de produto. Toda vez que um novo produto era listado, ele tinha que editar o arquivo de rotas; se esquecesse de um, o resultado era um erro 404. Alice não conseguia encontrar os produtos, e a taxa de reclamações disparou.

(2) Solução com Roteamento por Arquivos do Nuxt

Com o roteamento baseado em arquivos do Nuxt 3, Bob só precisa criar um arquivo:

TEXT 📖 Somente leitura
pages/products/[id].vue  →  /products/:id

Um milhão de produtos em um único arquivo, com parâmetros dinâmicos passados automaticamente.

(3) Benefícios: Roteamento Zero-Config

Bob não precisa mais escrever configurações de rotas—adicionar uma nova página é tão simples quanto criar um novo arquivo, e 1 milhão de páginas de detalhes de produtos requerem apenas um [id].vue.


3. Regras de Roteamento por Arquivos

(1) Processo de Mapeamento de Diretório para Rota

100%
flowchart LR
    A[pages/index.vue] -->|"/"| B[Rota Raiz]
    C[pages/about.vue] -->|"/about"| C2[Rota About]
    D[pages/products/index.vue] -->|"/products"| D2[Rota Lista de Produtos]
    E[pages/products/[id].vue] -->|"/products/:id"| E2[Rota Detalhe do Produto]
    F[pages/categories/[...slug].vue] -->|"/categories/:slug*"| F2[Rota Catch-all]

(2) Regras de Mapeamento de Roteamento por Arquivos

Caminho do Arquivo Rota Gerada Descrição
pages/index.vue / Home
pages/about.vue /about Página estática
pages/products/index.vue /products Lista de Produtos
pages/products/[id].vue /products/:id Parâmetro Dinâmico
pages/categories/[slug].vue /categories/:slug Parâmetros Dinâmicos
pages/categories/[...slug].vue /categories/:slug(*) Rota curinga
pages/404.vue /404 404 Personalizado

(1) ▶Exemplo: Roteamento Básico de Página

VUE
<!-- pages/index.vue -->
<template>
  <div>
    <h1>MegaShop - Milhões de Produtos</h1>
    <NuxtLink to="/products">Navegar Produtos</NuxtLink>
  </div>
</template>

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida
VUE
<!-- pages/about.vue -->
<template>
  <div>
    <h1>Sobre a MegaShop</h1>
    <p>Atendendo mais de 1 milhão de produtos mundialmente</p>
  </div>
</template>

4. Rotas Dinâmicas

(1) Rota Dinâmica com Parâmetro Único

Use a sintaxe [param] para definir parâmetros de rota dinâmica.

(1) ▶Exemplo: Rota Dinâmica para Páginas de Detalhes de Produtos

VUE
<!-- pages/products/[id].vue -->
<template>
  <div>
    <h1>Produto #{{ route.params.id }}</h1>
    <p>Preço: ${{ product?.price }} USD</p>
  </div>
</template>

<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)
</script>

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida

(2) Rotas Curinga

Use a sintaxe [...slug] para capturar caminhos multi-nível.

(2) ▶Exemplo: Rota Curinga de Categorias Multi-Nível

VUE
<!-- pages/categories/[...slug].vue -->
<template>
  <div>
    <h1>Categoria: {{ slugPath }}</h1>
    <p>{{ products.length }} produtos encontrados</p>
  </div>
</template>

<script setup lang="ts">
const route = useRoute()
// /categories/electronics/headphones → slug = ['electronics', 'headphones']
const slugPath = computed(() => (route.params.slug as string[]).join('/'))
const { data: products } = await useFetch(`/api/categories/${slugPath.value}`)
</script>

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida

(3) Tipos de Parâmetros de Rotas Dinâmicas

Sintaxe Correspondência URL de Exemplo Valor de params
[id] Segmento único /products/123 { id: '123' }
[id].vue + index.vue Opcional /products ou /products/123 { id?: '123' }
[...slug] Curinga multi-segmento /a/b/c { slug: ['a','b','c'] }

5. Rotas Aninhadas

(1) Estrutura de Rotas Aninhadas

Rotas aninhadas requerem uma página pai (um arquivo .vue com o mesmo nome) e um diretório filho trabalhando juntos:

TEXT 📖 Somente leitura
pages/
├── products/
│   ├── index.vue          # /products (filho)
│   ├── [id].vue           # /products/:id (filho)
│   └── edit.vue           # /products/edit (filho)
└── products.vue           # /products (pai com <NuxtPage />)

(1) ▶Exemplo: Rotas Aninhadas na Página de Produtos

VUE
<!-- pages/products.vue - Layout pai -->
<template>
  <div>
    <nav class="product-nav">
      <NuxtLink to="/products">Todos os Produtos</NuxtLink>
      <NuxtLink to="/products/featured">Destaques</NuxtLink>
    </nav>
    <!-- Rotas filhas renderizam aqui -->
    <NuxtPage />
  </div>
</template>

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida
VUE
<!-- pages/products/index.vue - Filho: lista de produtos -->
<template>
  <div>
    <h1>Todos os Produtos</h1>
    <p>1 milhão de produtos disponíveis</p>
  </div>
</template>
VUE
<!-- pages/products/[id].vue - Filho: detalhe do produto -->
<template>
  <div>
    <h1>Detalhe do Produto</h1>
    <p>ID: {{ route.params.id }}</p>
  </div>
</template>

(2) Comparação de Rotas Aninhadas vs. Layout

Dimensão Rotas Aninhadas Layout
Mecanismo Página pai + slot NuxtPage layouts/ + NuxtLayout
Relacionamento de Rotas Rotas Pai-Filho Compartilhando Layouts Troca de Layout em Nível de Página
Recuperação de Dados Pai e filho cada um usa useFetch Layout não busca dados
Casos de Uso Hierarquia Categoria → Produto → Review Layout Geral de Página (Header/Footer)

6. Navegação Programática

(1) Comparação de Três Métodos de Navegação

API Propósito Disponível no Servidor Caso de Uso
navigateTo() Navegação programática ✅ Redirecionamento após login
useRouter().push() Navegação no lado do cliente ❌ Navegação via clique de botão
NuxtLink Links Declarativos ✅ Navegação em Templates

(1) ▶Exemplo: Redirecionamento no Lado do Servidor com navigateTo

TYPESCRIPT
// No middleware ou contexto do lado do servidor
export default defineNuxtRouteMiddleware((to) => {
  const isAuthenticated = useState('isAuthenticated')

  if (!isAuthenticated.value && to.path.startsWith('/admin')) {
    return navigateTo('/login', { redirectCode: 302 })
  }
})

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida

(2) ▶Exemplo: Navegação no lado do cliente com useRouter

VUE
<template>
  <button @click="goToProduct(product.id)">
    Ver Detalhes
  </button>
</template>

<script setup lang="ts">
const router = useRouter()

function goToProduct(id: number) {
  router.push(`/products/${id}`)
}
</script>

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida

(3) ▶Exemplo: Obtendo parâmetros com useRoute

VUE
<script setup lang="ts">
const route = useRoute()

// Acessar params
const productId = route.params.id         // De [id].vue
const categorySlug = route.params.slug     // De [...slug].vue

// Acessar query params
// /products?category=electronics&sort=price
const category = route.query.category      // 'electronics'
const sort = route.query.sort              // 'price'
</script>

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida

7. Guia Prático de Rotas Multi-Nível na MegaShop

(1) Plano de Rotas da MegaShop

URL Arquivo Função
/ pages/index.vue Home
/products pages/products/index.vue Lista de Produtos
/products/[id] pages/products/[id].vue Detalhes do Produto
/categories/[category] pages/categories/[category].vue Página de Categoria
/categories/[category]/[subcategory] pages/categories/[...slug].vue Subcategoria
/cart pages/cart.vue Carrinho de Compras
/checkout pages/checkout.vue Página de Checkout
/admin pages/admin/index.vue Painel de Administração
/admin/products pages/admin/products/index.vue Gestão de Produtos
/404 pages/404.vue Página 404

(1) ▶Exemplo: Página 404 da MegaShop

VUE
<!-- pages/404.vue -->
<template>
  <div class="not-found">
    <h1>404 - Produto Não Encontrado</h1>
    <p>O produto que você está procurando não existe.</p>
    <NuxtLink to="/products">Navegar todos os produtos</NuxtLink>
  </div>
</template>

Saída:

TEXT 📖 Somente leitura
// Execução Bem-sucedida

8. Exemplo Completo: O Sistema de Rotas da MegaShop

VUE
<!-- pages/index.vue - Homepage -->
<template>
  <div>
    <section class="hero">
      <h1>MegaShop</h1>
      <p>Mais de 1 milhão de produtos, entregues mundialmente</p>
      <NuxtLink to="/products">Comprar Agora</NuxtLink>
    </section>
    <section class="featured">
      <ProductCard v-for="p in featured" :key="p.id" :product="p" />
    </section>
  </div>
</template>

<script setup lang="ts">
const { data: featured } = await useFetch('/api/products/featured')
</script>
VUE
<!-- pages/products/[id].vue - Detalhe do Produto -->
<template>
  <div v-if="product">
    <h1>{{ product.name }}</h1>
    <p class="price">${{ product.price }} USD</p>
    <button @click="addToCart">Adicionar ao Carrinho</button>
    <button @click="goBack">Voltar à Lista</button>
  </div>
  <div v-else>
    <p>Produto não encontrado</p>
    <NuxtLink to="/products">Navegar Produtos</NuxtLink>
  </div>
</template>

<script setup lang="ts">
const route = useRoute()
const router = useRouter()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

function addToCart() {
  navigateTo('/cart')
}

function goBack() {
  router.back()
}
</script>

❓Perguntas Frequentes

P Os parâmetros de rotas dinâmicas são strings ou números?
R Parâmetros de URL são sempre strings. Se precisar de números, converta manualmente: Number(route.params.id), ou deixe o tipo de retorno da API determinar o valor ao usar useFetch.
P Qual é a diferença entre [id].vue e [...slug].vue?
R [id] corresponde apenas um único segmento de caminho (/products/123), enquanto [...slug] corresponde um caminho multi-segmento (/a/b/c), onde slug é um array. Rotas catch-all são adequadas para categorias com número ilimitado de níveis.
P A página pai para uma rota aninhada precisa existir obrigatoriamente?
R Sim, uma rota aninhada só é formada quando tanto a página pai products.vue quanto o subdiretório products/ existem. Se você deseja apenas a rota filha, não crie a página pai.
P Qual é a diferença entre NuxtLink e uma tag a comum?
R NuxtLink é usado para navegação no lado do cliente (sem atualizar a página), enquanto a tag a aciona uma atualização completa da página. Use NuxtLink para navegação interna e a tag a para links externos.
P Como configurar uma página 404 personalizada?
R Basta criar um arquivo pages/404.vue. O Nuxt 3 exibe automaticamente esta página quando nenhuma rota corresponde à requisição. Você também pode lidar com isso em uma rota catch-all.
P Qual é a relação entre routeRules e rotas?
R routeRules são configurados no nuxt.config.ts para especificar estratégias de renderização (SSR/ISR/CSR) com base em caminhos de rotas; elas não afetam as definições de rotas. Rotas são definidas pelos arquivos no diretório pages/; routeRules apenas controlam o comportamento de renderização.

📖Resumo


📝Exercícios

  1. Exercício Básico (Dificuldade: ⭐): Crie pages/about.vue e pages/contact.vue, e verifique se as rotas são geradas automaticamente.
  2. Problema Avançado (Dificuldade ⭐⭐): Implemente roteamento dinâmico de dois níveis /products/[category]/[id] e exiba os parâmetros "category" e "id" na página.
  3. Desafio (Dificuldade: ⭐⭐⭐): Implemente uma rota catch-all [...slug].vue que possa renderizar caminhos multi-nível como /docs/getting-started/installation e exiba uma barra de navegação breadcrumb.

---|

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%