Nuxt 3 快速入门指南
什么是 Nuxt 3
Nuxt 3 是基于 Vue 3 的框架,提供了服务器端渲染(SSR)、静态生成(SSG)、混合渲染等能力,让开发者可以更方便地构建全栈 Web 应用。
Nuxt 的核心优势:
┌──────────────────────────────────┐
│ 1. 一站式解决方案 │
├──────────────────────────────────┤
│ ✅ Vue 3 组件框架
│ ✅ 服务器渲染(SSR)
│ ✅ 静态生成(SSG)
│ ✅ API 路由
│ ✅ 自动代码分割
│ ✅ 自动路由生成
│ ✅ 中间件系统
│ ✅ 插件系统
└──────────────────────────────────┘
1. 项目初始化
1.1 创建项目
# 使用官方脚手架
npx nuxi init my-nuxt-app
# 进入项目
cd my-nuxt-app
# 安装依赖
npm install
# 启动开发服务器
npm run dev
1.2 package.json 脚本
{
"scripts": {
"dev": "nuxt dev", // 开发模式(http://localhost:3000)
"build": "nuxt build", // 编译生产版本
"preview": "nuxt preview", // 预览生产构建
"generate": "nuxt generate", // 静态生成
"postinstall": "nuxt prepare" // 生成 TypeScript 配置
}
}
2. 项目文件结构
2.1 标准结构
my-nuxt-app/
├── .nuxt/ # 自动生成,包含编译产物
├── app.vue # 根组件
├── nuxt.config.ts # Nuxt 配置文件
├── package.json
│
├── pages/ # 页面组件(自动生成路由)
│ ├── index.vue # / 路由
│ ├── about.vue # /about 路由
│ └── product/
│ └── [id].vue # /product/:id 路由
│
├── components/ # 可复用组件(自动导入)
│ ├── Header.vue
│ ├── Footer.vue
│ └── Product/
│ └── Card.vue
│
├── layouts/ # 布局组件
│ ├── default.vue # 默认布局
│ └── admin.vue # 管理员布局
│
├── server/ # 服务器代码
│ └── api/
│ ├── products.ts
│ └── hello.ts
│
├── composables/ # 组合函数(自动导入)
│ ├── useAuth.ts
│ └── useFetch.ts
│
├── utils/ # 工具函数(自动导入)
│ └── helpers.ts
│
├── middleware/ # 路由中间件
│ ├── auth.ts
│ └── admin.ts
│
├── plugins/ # 插件
│ ├── vue-toastr.client.ts
│ └── analytics.ts
│
└── public/ # 静态资源
├── favicon.ico
└── logo.svg
2.2 nuxt.config.ts 配置
export default defineNuxtConfig({
// 生成目标
ssr: true, // 启用 SSR,设为 false 变成 SPA
// 开发配置
devtools: { enabled: true }, // Nuxt DevTools
// CSS 和样式
css: [
'@/assets/styles/main.css'
],
// 模块
modules: [
'@nuxt/content', // 内容管理
'@nuxt/image', // 图片优化
'@pinia/nuxt', // 状态管理
'nuxt-icon' // 图标库
],
// 路由
router: {
options: {
hashMode: false // URL 模式
}
},
// 性能
nitro: {
prerender: {
crawlLinks: true,
routes: ['/sitemap.xml']
}
}
})
3. 自动路由系统
3.1 基本路由
页面文件结构 生成的路由
pages/
├── index.vue → /
├── about.vue → /about
├── contact.vue → /contact
└── product/
└── index.vue → /product
3.2 动态路由
pages/
├── product/
│ ├── [id].vue → /product/:id
│ └── [id]/
│ └── review.vue → /product/:id/review
│
├── user/
│ └── [id]/
│ └── settings.vue → /user/:id/settings
3.3 路由参数访问
<!-- pages/product/[id].vue -->
<template>
<div>
<h1>产品 {{ id }}</h1>
<p>{{ product?.name }}</p>
</div>
</template>
<script setup lang="ts">
// 自动获取路由参数
const route = useRoute()
const id = route.params.id
// 获取查询参数
const search = route.query.search
// 编程式导航
const router = useRouter()
const goHome = () => {
router.push('/')
}
const goProductDetail = (productId: number) => {
router.push(`/product/${productId}`)
}
</script>
4. 布局系统
4.1 创建布局
<!-- layouts/default.vue -->
<template>
<div>
<Header />
<main>
<!-- 页面内容插入这里 -->
<slot />
</main>
<Footer />
</div>
</template>
<script setup lang="ts">
import Header from '@/components/Header.vue'
import Footer from '@/components/Footer.vue'
</script>
<style scoped>
main {
min-height: 100vh;
padding: 20px;
}
</style>
4.2 在页面中使用布局
<!-- pages/index.vue -->
<template>
<div>
<h1>首页</h1>
<p>内容</p>
</div>
</template>
<script setup lang="ts">
// 使用默认布局(自动)
definePageMeta({
layout: 'default'
})
// 或使用自定义布局
// definePageMeta({
// layout: 'admin'
// })
</script>
5. 数据获取
5.1 useFetch(Nuxt 推荐)
<template>
<div>
<p v-if="pending">加载中...</p>
<div v-else-if="data">
<h1>{{ data.title }}</h1>
<p>{{ data.description }}</p>
</div>
<p v-if="error">错误:{{ error.message }}</p>
</div>
</template>
<script setup lang="ts">
// useFetch 在 SSR 和客户端都能工作
const { data, pending, error, refresh } = await useFetch('/api/product/1')
// 重新获取数据
const reloadData = () => {
refresh()
}
</script>
5.2 useAsyncData
<template>
<div>
<p v-if="pending">加载中...</p>
<p v-else>{{ product?.name }}</p>
</div>
</template>
<script setup lang="ts">
const route = useRoute()
// 手动异步操作
const { data: product, pending } = await useAsyncData(
`product-${route.params.id}`, // 缓存键
async () => {
const response = await $fetch(`/api/product/${route.params.id}`)
return response
}
)
</script>
5.3 $fetch
<template>
<div>
<button @click="loadData">加载数据</button>
<p v-if="data">{{ data.name }}</p>
</div>
</template>
<script setup lang="ts">
const data = ref(null)
// 单独的数据请求(通常用于事件处理)
const loadData = async () => {
try {
data.value = await $fetch('/api/product/1')
} catch (error) {
console.error('获取失败:', error)
}
}
</script>
6. 服务器端路由
6.1 创建 API 路由
// server/api/products.ts
export default defineEventHandler(async (event) => {
// GET /api/products
return [
{ id: 1, name: '产品 A', price: 99 },
{ id: 2, name: '产品 B', price: 199 }
]
})
// server/api/products/[id].ts
export default defineEventHandler(async (event) => {
// GET /api/products/:id
const id = getRouterParam(event, 'id')
return {
id,
name: `产品 ${id}`,
price: 99 + parseInt(id) * 10
}
})
// server/api/products.post.ts
export default defineEventHandler(async (event) => {
// POST /api/products
const body = await readBody(event)
return {
success: true,
data: body
}
})
6.2 在客户端调用
<template>
<div>
<button @click="fetchProducts">获取产品</button>
<ul>
<li v-for="product in products" :key="product.id">
{{ product.name }} - ¥{{ product.price }}
</li>
</ul>
</div>
</template>
<script setup lang="ts">
const products = ref([])
const fetchProducts = async () => {
products.value = await $fetch('/api/products')
}
</script>
7. 组合函数和工具
7.1 创建组合函数
// composables/useProduct.ts
export const useProduct = () => {
const products = ref([])
const loading = ref(false)
const fetchProducts = async () => {
loading.value = true
try {
products.value = await $fetch('/api/products')
} finally {
loading.value = false
}
}
return {
products: readonly(products),
loading: readonly(loading),
fetchProducts
}
}
7.2 在组件中使用
<template>
<div>
<button @click="fetchProducts">加载产品</button>
<p v-if="loading">加载中...</p>
<ul v-else>
<li v-for="product in products" :key="product.id">
{{ product.name }}
</li>
</ul>
</div>
</template>
<script setup lang="ts">
// 自动导入(无需 import)
const { products, loading, fetchProducts } = useProduct()
onMounted(() => {
fetchProducts()
})
</script>
8. 中间件系统
8.1 创建中间件
// middleware/auth.ts
export default defineRouteMiddleware((to, from) => {
// 检查认证状态
const authStore = useAuthStore()
if (!authStore.isLoggedIn) {
return navigateTo('/login')
}
})
// middleware/admin.ts
export default defineRouteMiddleware((to, from) => {
const authStore = useAuthStore()
if (!authStore.isAdmin) {
return abortNavigation('无权访问')
}
})
8.2 使用中间件
<!-- pages/dashboard.vue -->
<template>
<div>
<h1>用户仪表板</h1>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: 'auth' // 应用中间件
})
</script>
<!-- pages/admin/index.vue -->
<template>
<div>
<h1>管理员面板</h1>
</div>
</template>
<script setup lang="ts">
definePageMeta({
middleware: ['auth', 'admin'] // 多个中间件
})
</script>
9. 常用模块
9.1 Pinia 状态管理
// stores/product.ts
import { defineStore } from 'pinia'
export const useProductStore = defineStore('product', () => {
const products = ref([])
const selectedProduct = ref(null)
const setProducts = (data) => {
products.value = data
}
const selectProduct = (id: number) => {
selectedProduct.value = products.value.find(p => p.id === id)
}
return {
products,
selectedProduct,
setProducts,
selectProduct
}
})
9.2 @nuxt/content 内容管理
<template>
<div>
<article>
<h1>{{ article.title }}</h1>
<ContentRenderer :value="article" />
</article>
</div>
</template>
<script setup lang="ts">
// 获取内容
const article = await queryContent('blog/first-post').findOne()
// 或查询多个
const posts = await queryContent('blog').find()
</script>
10. Nuxt 3 最佳实践
// ✅ 最佳实践
// 1. 使用 TypeScript
interface Product {
id: number
name: string
price: number
}
// 2. 使用自动导入的功能
// - 无需 import,直接使用 useState、useRoute、useRouter
// - 组件、中间件、插件自动导入
// 3. 服务器端代码与客户端分离
// - server/ 目录中的代码只在服务器运行
// - .server. 后缀的文件只在服务器运行
// 4. 正确处理 SSR
// 避免在 SSR 时访问浏览器 API
const handleClient = () => {
if (process.client) {
// 仅在客户端运行
window.alert('Hello')
}
}
// 5. 使用 SEO 组件
// 在 head 中定义元数据
useHead({
title: '产品列表',
meta: [
{ name: 'description', content: '查看所有产品' }
]
})
11. 部署
11.1 生产构建
# 构建用于 Node.js 服务器
npm run build
# 预览构建
npm run preview
# 静态生成(SSG)
npm run generate
11.2 部署选项
| 平台 | 说明 | 命令 |
|---|---|---|
| Vercel | 官方推荐,一键部署 | 连接 Git 即可 |
| Netlify | 支持 SSG 和 SSR | 连接 Git 即可 |
| Node.js 服务器 | 自托管 | node .output/server/index.mjs |
| Docker | 容器化部署 | 创建 Dockerfile |
总结
Nuxt 3 的核心优势:
- ✅ 开发体验优秀
- ✅ 自动路由和代码分割
- ✅ 完整的 SSR 支持
- ✅ 丰富的模块生态
- ✅ 很好的 SEO 支持
何时使用 Nuxt 3:
- 需要 SEO 的应用
- 需要快速开发
- 习惯 Vue 的开发者
- 需要全栈能力


