视图结构
Nuxt 给你 4 层来搭 UI:app.vue、组件、页面、布局。每一层分工明确,Nuxt 会自动连线,大多数时候你只要加文件就行。
app.vue
app.vue 是应用入口。如果完全不需要路由:
<template>
<div>
<h1>欢迎</h1>
</div>
</template>
想要多页面时挂上 <NuxtPage />:
<template>
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>
如果删掉 app.vue,Nuxt 会生成一个默认入口,相当于 <NuxtLayout><NuxtPage /></NuxtLayout>。
组件
app/components/ 下的所有内容会自动导入,不用手写 import:
app/components/
├── AppHeader.vue
├── AppFooter.vue
└── AppAlert.vue
<template>
<div>
<AppHeader />
<AppAlert>Hello,来自自动导入的组件。</AppAlert>
<AppFooter />
</div>
</template>
嵌套目录会变成名称前缀:app/components/base/Button.vue → <BaseButton />。
小建议:
- 在
<template>里统一用 PascalCase。 - 在组件名前加
Lazy可以延迟加载:<LazyAppHeavy />。
页面
页面放在 app/pages/,每个 .vue 文件就是一条路由:
app/pages/
├── index.vue → /
├── about.vue → /about
└── blog/
├── index.vue → /blog
└── [id].vue → /blog/:id
<!-- app/pages/about.vue -->
<template>
<section>
<h1>关于我们</h1>
</section>
</template>
页面会自动分包,<NuxtLink> 会帮你预取,definePageMeta({ … }) 用来声明页面级元信息。
布局
布局用来包裹一组页面,负责共用的外壳(头部、底部、侧边栏)。文件放在 app/layouts/:
<!-- app/layouts/default.vue -->
<template>
<div>
<AppHeader />
<slot />
<AppFooter />
</div>
</template>
default.vue 会自动应用。要自定义布局,页面级声明:
<script setup lang="ts">
definePageMeta({ layout: 'admin' })
</script>
<template>
<div>Dashboard</div>
</template>
……对应的文件放到 app/layouts/admin.vue。
<NuxtLayout> 与 <NuxtPage>
<NuxtPage />是文件式路由的“出口”,负责流式渲染、预取、过渡。<NuxtLayout>决定当前页面用哪个布局,也可以手动指定name:
<NuxtLayout name="admin">
<NuxtPage />
</NuxtLayout>
如果只有一个布局,完全可以跳过 layouts/,把外壳直接写在 app.vue 里。
要点回顾
| 需求 | 去哪儿 |
|---|---|
| 根入口/全站外壳 | app.vue(或单布局) |
| 可复用 UI 块 | app/components/ |
| 一条路由 + 视图 | app/pages/ |
| 多页面共享的外壳 | app/layouts/ |
进阶:定制 HTML 模板
如果 useHead 还不够(需要改 Nitro 输出的原始 HTML),用 render:html 钩子写一个 Nitro 插件:
// server/plugins/meta.ts
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('render:html', (html, { event }) => {
html.head.push('<meta name="description" content="自定义描述" />')
})
})
这种写法谨慎使用 —— useHead 能覆盖 99% 的情况,静态资源和 SEO 章节会介绍更顺手的做法。