Páginas e Rotas
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
- Roteamento por Arquivos: Regras completas de mapeamento para o diretório
pages/ - Rotas Dinâmicas: Captura de Parâmetros em [id].vue e [...slug].vue
- Rotas Aninhadas e Layouts: Página Pai + Slots Filhos Aninhados
- Navegação programática: navigateTo() / useRouter() / useRoute()
- Guia Prático de Rotas Dinâmicas Multi-Nível na MegaShop
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:
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
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
<!-- pages/index.vue -->
<template>
<div>
<h1>MegaShop - Milhões de Produtos</h1>
<NuxtLink to="/products">Navegar Produtos</NuxtLink>
</div>
</template>
Saída:
// Execução Bem-sucedida
<!-- 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
<!-- 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:
// 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
<!-- 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:
// 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:
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
<!-- 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:
// Execução Bem-sucedida
<!-- 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>
<!-- 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
// 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:
// Execução Bem-sucedida
(2) ▶Exemplo: Navegação no lado do cliente com useRouter
<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:
// Execução Bem-sucedida
(3) ▶Exemplo: Obtendo parâmetros com useRoute
<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:
// 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
<!-- 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:
// Execução Bem-sucedida
8. Exemplo Completo: O Sistema de Rotas da MegaShop
<!-- 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>
<!-- 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
Number(route.params.id), ou deixe o tipo de retorno da API determinar o valor ao usar useFetch.slug é um array. Rotas catch-all são adequadas para categorias com número ilimitado de níveis.products.vue quanto o subdiretório products/ existem. Se você deseja apenas a rota filha, não crie a página pai.a comum?a aciona uma atualização completa da página. Use NuxtLink para navegação interna e a tag a para links externos.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.routeRules e rotas?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
- Roteamento por Arquivos do Nuxt 3: Arquivos sob
pages/são mapeados automaticamente para rotas com configuração zero - Rotas dinâmicas usam [id].vue para capturar um único parâmetro e [...slug].vue para capturar caminhos multi-nível
- Rotas aninhadas requerem uma página pai com o mesmo nome + um slot NuxtPage; este é um conceito diferente de Layout.
- Navegação programática: Use
navigateTo()no servidor euseRouter().push()no cliente - MegaShop: Um Milhão de Produtos em Apenas Um Arquivo [id].vue
📝Exercícios
- Exercício Básico (Dificuldade: ⭐): Crie pages/about.vue e pages/contact.vue, e verifique se as rotas são geradas automaticamente.
- 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. - Desafio (Dificuldade: ⭐⭐⭐): Implemente uma rota catch-all [...slug].vue que possa renderizar caminhos multi-nível como
/docs/getting-started/installatione exiba uma barra de navegação breadcrumb.
---|



