Nuxt4 进阶 API 与隐藏技巧
Nuxt4 除了
useFetch、useRoute这些核心 API 外,还有大量"知道了就很有用、不知道就不会用"的进阶 API。callOnce避免重复初始化、useRequestURL拿到 SSR 安全的 URL、prerenderRoutes动态注册预渲染路由、clearNuxtData手动清缓存——这些 API 在特定场景下能解决棘手问题。本章按使用场景分类,讲解 30 个进阶 API 和隐藏技巧。
1. 执行控制
技巧 1:callOnce — 只执行一次
callOnce 确保一个函数在 SSR + CSR 的生命周期中只执行一次,即使组件被多次渲染。
<script setup lang="ts">
// 应用初始化逻辑(只在首次访问时执行,不会在每次导航时重复)
await callOnce('init-analytics', async () => {
await $fetch('/api/analytics/init', { method: 'POST' })
})
</script>典型场景:
- 初始化第三方 SDK(只需一次)
- 记录首次访问日志
- 全局数据预加载
技巧 2:callOnce 配合 mode 参数
// 只在服务端执行一次
await callOnce('server-init', () => initServerCache(), { mode: 'server' })
// 只在客户端执行一次
await callOnce('client-init', () => initClientSDK(), { mode: 'client' })
// 每次导航都执行(但不重复)
await callOnce('page-view', () => trackPageView(), { mode: 'navigation' })技巧 3:useRequestURL — SSR 安全的 URL
// ❌ SSR 时 window.location 不存在
const url = window.location.href
// ✅ SSR/CSR 都能用
const url = useRequestURL()
console.log(url.pathname) // /video/123
console.log(url.origin) // https://example.com
console.log(url.searchParams.get('q')) // 搜索关键词场景:生成分享链接、获取当前 URL 参数、判断域名。
技巧 4:useRequestHeaders — 读取请求头
// 在组件或 composable 中获取请求头(SSR 时有值)
const headers = useRequestHeaders(['cookie', 'accept-language'])
const lang = headers['accept-language']?.split(',')[0]场景:服务端渲染时需要根据 Accept-Language 决定语言。
2. 数据管理
技巧 5:refreshNuxtData — 刷新所有数据
// 刷新所有 useAsyncData / useFetch 的数据
await refreshNuxtData()
// 只刷新指定 key 的数据
await refreshNuxtData('video-list')
// 使用场景:用户操作后需要刷新列表
async function handleDelete(id: string) {
await $fetch(`/api/videos/${id}`, { method: 'DELETE' })
await refreshNuxtData('video-list')
}技巧 6:clearNuxtData — 手动清缓存
// 清除指定 key 的缓存数据
clearNuxtData('video-list')
// 清除匹配的所有缓存
clearNuxtData((key) => key.startsWith('video-'))
// 场景:用户登出时清除所有用户相关的缓存
function handleLogout() {
clearNuxtData((key) => key.startsWith('user-'))
navigateTo('/login')
}技巧 7:useNuxtData — 跨组件读缓存
// 页面 A 加载了数据
const { data } = await useFetch('/api/videos', { key: 'videos' })
// 页面 B 中直接读取缓存(不发请求)
const { data: cachedVideos } = useNuxtData('videos')
// 如果缓存为空,说明用户直接访问了页面 B技巧 8:useState 高级用法
// 跨请求隔离的全局状态(SSR 安全)
const useGlobalLoading = () => useState('global-loading', () => false)
// 初始化函数只执行一次(SSR 时服务端执行,结果传给客户端)
const useCurrentUser = () => useState<User | null>('current-user', () => null)
// 共享到服务端和客户端
const useLocale = () => useState('locale', () => 'zh-CN')3. 路由与导航
技巧 9:prerenderRoutes — 动态注册预渲染
<script setup lang="ts">
// 在页面中声明需要预渲染的路由
prerenderRoutes(['/about', '/contact', '/faq'])
</script>// 或在 API 路由中动态生成
// server/api/__sitemap.ts
export default defineEventHandler(async () => {
const videos = await db.select({ id: videos.id }).from(videosTable)
return videos.map(v => `/video/${v.id}`)
})场景:nuxi generate 静态生成时,让 Nuxt 知道有哪些动态路由需要预渲染。
技巧 10:useRouter 编程式导航进阶
const router = useRouter()
// 替换当前路由(不加入历史记录)
router.replace({ query: { page: 2 } })
// 导航前钩子
router.beforeEach((to, from) => {
if (to.meta.requiresAuth && !isLoggedIn.value) {
return navigateTo('/login')
}
})
// 导航后钩子(适合记录页面浏览)
router.afterEach((to) => {
trackPageView(to.fullPath)
})技巧 11:NuxtRouteAnnouncer — 无障碍路由通知
<!-- app.vue -->
<template>
<NuxtRouteAnnouncer />
<NuxtLayout>
<NuxtPage />
</NuxtLayout>
</template>当页面切换时,屏幕阅读器会读出新页面的标题。对视障用户友好。
技巧 12:definePageMeta 高级选项
<script setup lang="ts">
definePageMeta({
// 路由中间件
middleware: ['auth', 'admin'],
// 布局
layout: 'admin',
// 页面切换动画
pageTransition: { name: 'slide-left', mode: 'out-in' },
// 自定义 key(控制组件复用)
key: route => route.fullPath,
// 路由验证(不匹配时返回 404)
validate: async (route) => {
return /^\d+$/.test(route.params.id as string)
},
// 路由别名
alias: ['/v/:id'],
})
</script>4. 预览与调试
技巧 13:usePreviewMode — 预览未发布内容
const { enabled, state } = usePreviewMode()
// 在 API 路由中根据预览模式返回草稿
export default defineEventHandler(async (event) => {
const preview = getQuery(event).preview === 'true'
const where = preview ? {} : { status: 'published' }
return db.select().from(videos).where(where)
})场景:CMS 系统中,编辑者可以预览未发布的文章/视频。
技巧 14:showError / clearError
// 手动触发全屏错误页
showError({
statusCode: 403,
message: '你没有权限访问此页面',
})
// 在错误页面清除错误(返回正常页面)
clearError({ redirect: '/' })技巧 15:useError — 读取当前错误
<!-- error.vue -->
<script setup lang="ts">
const error = useError()
</script>
<template>
<div class="error-page">
<h1>{{ error?.statusCode }}</h1>
<p>{{ error?.message }}</p>
<button @click="clearError({ redirect: '/' })">返回首页</button>
</div>
</template>5. 渲染控制
技巧 16:useHydration — 自定义序列化
// 在 SSR 时序列化自定义数据到 payload,客户端 hydration 时恢复
useHydration('my-data', () => {
// SSR 时序列化
return { timestamp: Date.now(), config: getConfig() }
}, (data) => {
// CSR hydration 时恢复
Object.assign(myStore, data)
})技巧 17:defineRouteRules — 页面级渲染策略
<script setup lang="ts">
defineRouteRules({
// 此页面使用 ISR(增量静态再生)
swr: 60 * 10, // 10 分钟缓存
})
</script>// 或在 nuxt.config.ts 中统一配置
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true }, // 首页静态生成
'/video/**': { swr: 600 }, // 视频页 ISR
'/admin/**': { ssr: false }, // 管理后台 SPA
'/api/**': { cors: true }, // API 允许跨域
},
})技巧 18:NuxtIsland — 服务端组件
<!-- 父组件(客户端) -->
<template>
<NuxtIsland name="HeavyChart" :props="{ data: chartData }" />
</template>
<!-- components/islands/HeavyChart.vue(只在服务端渲染) -->
<script setup lang="ts">
const props = defineProps<{ data: ChartData }>()
// 复杂计算在服务端完成,只发送 HTML 到客户端
const result = heavyComputation(props.data)
</script>场景:计算密集型组件在服务端渲染,不增加客户端 JS 体积。
6. 插件与模块
技巧 19:defineNuxtPlugin 提供全局函数
// plugins/toast.ts
export default defineNuxtPlugin(() => {
return {
provide: {
toast: (message: string, type: 'success' | 'error' = 'success') => {
// toast 逻辑
},
},
}
})
// 使用
const { $toast } = useNuxtApp()
$toast('操作成功', 'success')技巧 20:插件依赖排序
// plugins/01.auth.ts(数字前缀控制顺序)
export default defineNuxtPlugin({
name: 'auth',
dependsOn: ['session'], // 显式声明依赖
setup() {
// 确保 session 插件先初始化
},
})技巧 21:defineNuxtModule — 创建项目内部模块
// modules/auto-import-icons.ts
export default defineNuxtModule({
meta: { name: 'auto-import-icons' },
setup(options, nuxt) {
nuxt.hook('components:dirs', (dirs) => {
dirs.push({
path: resolve('./assets/icons'),
prefix: 'Icon',
})
})
},
})7. Server 端进阶
技巧 22:server/middleware 全局钩子
// server/middleware/log.ts(所有请求都会经过)
export default defineEventHandler((event) => {
const start = Date.now()
event.node.res.on('finish', () => {
const duration = Date.now() - start
console.log(`${event.method} ${event.path} ${duration}ms`)
})
})技巧 23:server/plugins — 服务端生命周期
// server/plugins/db.ts
export default defineNitroPlugin((nitro) => {
// 服务器启动时
nitro.hooks.hook('request', (event) => {
// 每个请求之前
})
nitro.hooks.hook('close', () => {
// 服务器关闭时(清理数据库连接等)
})
})技巧 24:服务端存储 useStorage
// 使用 Nitro 内置的 KV 存储(内存/Redis/文件系统)
export default defineEventHandler(async () => {
const storage = useStorage('cache')
// 读取
const cached = await storage.getItem('popular-tags')
if (cached) return cached
// 写入
const tags = await db.select().from(tagsTable).limit(20)
await storage.setItem('popular-tags', tags, { ttl: 300 })
return tags
})8. 构建与部署
技巧 25:nuxt.config.ts 条件配置
export default defineNuxtConfig({
$production: {
devtools: { enabled: false },
},
$development: {
devtools: { enabled: true },
},
$test: {
// 测试环境特定配置
},
})技巧 26:extends 继承配置
// nuxt.config.ts — 继承基础配置
export default defineNuxtConfig({
extends: ['./base-layer'], // 继承 base-layer 的组件、composables、pages
})场景:多个项目共享同一套组件库和配置。
技巧 27:app:manifests 自动更新
export default defineNuxtConfig({
experimental: {
appManifest: true, // 启用后,SPA 导航时检查新版本
},
})客户端导航时,Nuxt 检查 manifest 是否有更新。有新版本时,下次整页刷新会加载新代码。
技巧 28:useAppConfig + app.config.ts
// app.config.ts(支持 HMR,不需要重启)
export default defineAppConfig({
theme: { primary: '#3b82f6' },
features: { comments: true, likes: true },
})
// 使用
const config = useAppConfig()
if (config.features.comments) {
// 显示评论功能
}技巧 29:自定义 Nitro preset
export default defineNuxtConfig({
nitro: {
preset: 'node-server', // 默认 Node.js
// preset: 'cloudflare-pages', // Cloudflare
// preset: 'vercel-edge', // Vercel Edge
// preset: 'bun', // Bun runtime
},
})技巧 30:useRuntimeConfig 的类型增强
// 在 nuxt.config.ts 中声明
export default defineNuxtConfig({
runtimeConfig: {
secretKey: '',
public: { apiBase: '' },
},
})
// 自动生成类型到 .nuxt/types/
// 使用时完整类型提示:
const config = useRuntimeConfig()
config.secretKey // string(服务端)
config.public.apiBase // string(客户端+服务端)本章小结
30 个进阶技巧按场景分类:
- 执行控制(1-4):callOnce 避免重复、useRequestURL SSR 安全 URL、useRequestHeaders 读取请求头
- 数据管理(5-8):refreshNuxtData 刷新、clearNuxtData 清缓存、useNuxtData 跨组件读取、useState 全局状态
- 路由导航(9-12):prerenderRoutes 动态预渲染、NuxtRouteAnnouncer 无障碍、definePageMeta 高级选项
- 预览调试(13-15):usePreviewMode 草稿预览、showError/clearError 错误控制
- 渲染控制(16-18):useHydration 自定义序列化、routeRules 页面级策略、NuxtIsland 服务端组件
- 插件模块(19-21):provide 全局函数、插件依赖排序、defineNuxtModule 内部模块
- Server 端(22-24):全局中间件、服务端插件、useStorage KV 缓存
- 构建部署(25-30):条件配置、extends 继承、appManifest 自动更新、Nitro preset