这是一份快速参考速查表,包含 Nuxt.js 的核心 API 参考列表和一些示例。
使用 nuxi(Nuxt CLI)创建新项目:
npx nuxi init <project-name>
# or
yarn dlx nuxi init <project-name>
# or
pnpm dlx nuxi init <project-name>
进入项目目录并安装依赖:
cd <project-name>
npm install
# or
yarn install
# or
pnpm install
运行 npm run dev 或 yarn dev 或 pnpm dev 以在 http://localhost:3000 上启动开发服务器。
使用以下内容创建或填充 pages/index.vue:
<template>
  <div>Welcome to Nuxt.js!</div>
</template>
<script setup>
// Nuxt 3 中,<script setup> 是推荐的写法
// 无需显式导出组件
</script>
Nuxt.js 也是围绕页面的概念构建的。 页面是 pages 目录中的 .vue 文件。 Nuxt 会自动根据文件结构生成路由。
Nuxt 3 推荐使用 useFetch 或 useAsyncData 进行数据获取,它们在服务器端和客户端都能工作,并处理 SSR 数据传递。
<template>
  <div>
    <p v-if="pending">Loading...</p>
    <pre v-else-if="error">Error: {{ error.message }}</pre>
    <pre v-else>{{ data }}</pre>
  </div>
</template>
<script setup>
// 'useFetch' 是 'useAsyncData' 加上 fetch 的快捷方式
const { data, pending, error, refresh } = await useFetch('/api/data', {
  // 可以提供选项,如 pick, transform, server, lazy 等
  // pick: ['id', 'title'] // 只选择需要的字段
});
// 或者使用 useAsyncData + $fetch (Nuxt 内置的 fetch 封装)
/*
const { data, pending, error, refresh } = await useAsyncData(
  'myData', // 唯一的 key
  () => $fetch('/api/data')
)
*/
// 如果需要在 setup 外或非 setup 脚本中使用,移除 await
// const { data, pending, error } = useFetch('/api/data');
</script>
useFetch 和 useAsyncData 在服务器端执行以进行 SSR。获取的数据会被序列化并传递给客户端。pending: 请求是否进行中。error: 请求是否出错。data: 返回的数据 (ref)。refresh: 手动重新获取数据的函数。lazy: true: 数据在客户端导航后加载,显示加载状态,不阻塞导航。server: false: 只在客户端获取数据。Nuxt 3 通过 Nitro 服务器引擎支持强大的 SSG 功能。
useFetch 或 useAsyncData 获取页面数据。npx nuxi generate 命令。<NuxtLink>)并预渲染这些页面。pages/posts/[id].vue),如果 Nuxt 无法自动发现所有可能的路径,你需要在 nuxt.config.ts 中配置预渲染路由:// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    prerender: {
      // crawlLinks: true, // 默认开启,爬取链接
      routes: ['/', '/about', '/posts/1', '/posts/2'] // 手动指定需要预渲染的路由
      // 也可以异步获取路由列表
      /*
      async routes() {
        const posts = await $fetch('/api/posts'); // 假设有获取所有 post ID 的 API
        return posts.map(post => `/posts/${post.id}`);
      }
      */
    }
  }
})
Nuxt 3 (Nitro) 允许在页面或 API 级别配置缓存策略,实现类似 ISR/SWR 的效果。
在 nuxt.config.ts 中使用 routeRules 配置:
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // 对 /blog/** 下的所有页面应用 ISR,缓存 60 秒
    '/blog/**': { isr: 60 }, // 单位:秒
    // 对特定页面应用 SWR,缓存 1 小时,后台更新
    '/products/special': { swr: 3600 },
    // 对 API 路由应用缓存
    '/api/posts': { swr: 600 },
    // 禁用 SSR,仅 CSR
    '/admin/**': { ssr: false },
    // 重定向
    '/old-page': { redirect: '/new-page' },
    // 添加 headers
    '/assets/**': { headers: { 'cache-control': 's-maxage=31536000' } },
  }
})
isr: <seconds>: 在指定时间内提供缓存,过期后下一个请求会触发后台重新生成。swr: <seconds>: 在指定时间内提供缓存,过期后下一个请求立即返回旧缓存,同时触发后台重新生成。nuxi build 的输出 (.output 目录)。如果数据仅在客户端需要(例如,用户特定数据且不需要 SEO),可以在 onMounted 钩子中使用原生 fetch 或 $fetch。
<template>
  <div>
    <p v-if="loading">Loading profile...</p>
    <div v-else-if="profile">
      <h1>{{ profile.name }}</h1>
      <p>{{ profile.bio }}</p>
    </div>
    <p v-else>No profile data</p>
  </div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const profile = ref(null)
const loading = ref(true)
onMounted(async () => {
  try {
    // $fetch 是 Nuxt 提供的 fetch 封装,更好用
    profile.value = await $fetch('/api/profile-data')
  } catch (error) {
    console.error('Failed to load profile data:', error)
  } finally {
    loading.value = false
  }
})
</script>
注意: 这种方式获取的数据不会用于 SSR,可能影响首屏加载内容和 SEO。通常推荐使用 useFetch 或 useAsyncData 并设置 server: false 或 lazy: true 来实现类似效果,同时利用 Nuxt 的状态管理和错误处理。
Nuxt 在项目根目录的 public/ 文件夹下提供静态文件。代码可以从根 URL (/) 引用这些文件。
<template>
  <!-- public/avatar.png -->
  <img src="/avatar.png" alt="User Avatar" width="64" height="64">
  <!-- 使用 NuxtImg (如果安装了 @nuxt/image) -->
  <NuxtImg src="/avatar.png" alt="User Avatar" width="64" height="64" />
</template>
<script setup>
// 如果使用 @nuxt/image
// import { NuxtImg } from '#components' // 通常 Nuxt 会自动导入
</script>
Nuxt (基于 Vite) 默认目标是支持 原生 ES 模块、原生 ESM 动态导入 和 import.meta 的现代浏览器。
可以通过 nuxt.config.ts 中的 vite.build.target 或 .browserslistrc 文件配置目标浏览器(Vite 会使用 browserslist 配置)。
// nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    build: {
      target: 'es2015' // 或 'modules' (默认)
    }
  }
})
在 nuxt.config.ts 的 css 数组中引入全局 CSS 文件。通常放在 assets/css/ 目录下。
// nuxt.config.ts
export default defineNuxtConfig({
  css: [
    '~/assets/css/main.css', // 使用 ~ 代替 @ 指向 srcDir (通常是项目根目录)
  ],
})
例如,assets/css/main.css:
body {
  font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  margin: 0 auto;
}
这些样式会被打包并全局应用。
同样在 nuxt.config.ts 的 css 数组中引入:
// nuxt.config.ts
export default defineNuxtConfig({
  css: [
    'bootstrap/dist/css/bootstrap.css', // 直接从 node_modules 引入
    '~/assets/css/main.css',
  ],
})
Vue 组件天然支持 Scoped CSS 和 CSS Modules。
Scoped CSS: (最常用)
<template>
  <button class="button error">Destroy</button>
</template>
<style scoped>
/* 样式只作用于当前组件 */
.button {
  padding: 8px 16px;
}
.error {
  color: white;
  background-color: red;
}
</style>
CSS Modules:
<template>
  <!-- 使用 $style 对象绑定 class -->
  <button :class="$style.error">Destroy</button>
</template>
<style module>
/* 生成带 hash 的唯一类名, 如 .Button_error_hash */
.error {
  color: white;
  background-color: blue; /* 改为蓝色以区分 */
}
</style>
Nuxt (通过 Vite) 内置了对 CSS 预处理器的支持。只需安装相应的预处理器即可。
# 安装 Sass
npm install --save-dev sass
# or yarn add --dev sass
# or pnpm add -D sass
# 安装 Less
npm install --save-dev less
# or yarn add --dev less
# or pnpm add -D less
安装后,可以直接在 .vue 文件或 assets 目录中使用 .scss, .sass, .less, .styl 文件。
<style lang="scss" scoped>
$primary-color: #41B883; // Vue Green
.button {
  background-color: $primary-color;
  &:hover {
    opacity: 0.8;
  }
}
</style>
在 nuxt.config.ts 中通过 vite.css.preprocessorOptions 配置。
// nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          // 自动导入全局变量/mixins
          additionalData: '@import "~/assets/scss/_variables.scss"; @import "~/assets/scss/_mixins.scss";',
        },
        less: {
          // Less 配置
          modifyVars: {
            'primary-color': '#1DA57A',
          },
          javascriptEnabled: true,
        }
      }
    }
  }
})
/* assets/scss/_variables.scss */
$primary-color: #3498db;
$secondary-color: #f1c40f;
然后在 nuxt.config.ts 中配置 additionalData 如上。之后就可以在任何 .vue 的 <style lang="scss"> 中直接使用 $primary-color。
Vue 生态更倾向于使用 <style scoped> 或 CSS Modules。如果需要 CSS-in-JS,可以选择社区库如 emotion 或 styled-components-vue,并自行配置。
创建 layouts/default.vue 文件。这个布局会自动应用到所有未使用其他布局的页面。
// layouts/default.vue
<template>
  <div>
    <header>
      <nav>
        <NuxtLink to="/">Home</NuxtLink> |
        <NuxtLink to="/about">About</NuxtLink>
      </nav>
    </header>
    <main>
      <slot /> <!-- 页面内容会渲染在这里 -->
    </main>
    <footer>
      <p>© 2023 My Nuxt App</p>
    </footer>
  </div>
</template>
创建其他 .vue 文件在 layouts/ 目录下,例如 layouts/admin.vue。
// layouts/admin.vue
<template>
  <div class="admin-layout">
    <aside>Admin Sidebar</aside>
    <main>
      <slot />
    </main>
  </div>
</template>
在页面的 <script setup> 中使用 definePageMeta:
// pages/admin/dashboard.vue
<template>
  <div>Admin Dashboard Content</div>
</template>
<script setup>
definePageMeta({
  layout: 'admin' // 指定使用 admin.vue 布局
})
</script>
或者直接在页面模板中使用 <NuxtLayout name="admin">:
// pages/admin/settings.vue
<template>
  <NuxtLayout name="admin">
    <div>Admin Settings Content</div>
    <!-- 也可以在这里添加布局特定的内容 -->
  </NuxtLayout>
</template>
(注: 使用 definePageMeta 更常见和推荐)
// pages/login.vue - 不需要导航和页脚的页面
<template>
  <div>Login Form</div>
</template>
<script setup>
definePageMeta({
  layout: false // 禁用所有布局
})
</script>
可以在布局组件中获取共享数据。
// layouts/default.vue
<template>
  <div>
    <header>
      <nav v-if="!pending && navigationData">
        <NuxtLink v-for="link in navigationData.links" :key="link.path" :to="link.path">
          {{ link.name }}
        </NuxtLink>
      </nav>
      <p v-else>Loading navigation...</p>
    </header>
    <main>
      <slot />
    </main>
    <footer>...</footer>
  </div>
</template>
<script setup>
// 获取在所有页面共享的导航数据
const { data: navigationData, pending } = await useFetch('/api/navigation', { lazy: true });
</script>
注意: 在布局中使用 await 会阻塞所有使用该布局的页面的渲染,直到数据获取完成。通常建议使用 lazy: true 或将数据获取移到 Pinia/状态管理中。
需要先安装模块: npm install -D @nuxt/image 或 yarn add -D @nuxt/image 或 pnpm add -D @nuxt/image,然后在 nuxt.config.ts 中添加 '@nuxt/image' 到 modules 数组。
<template>
  <h1>My Homepage</h1>
  <NuxtImg
    src="/me.png"
    alt="Picture of the author"
    width="500"
    height="500"
    format="webp"
    quality="80"
    placeholder="/placeholder.svg" <!-- 可选的占位符 -->
  />
  <p>Welcome!</p>
</template>
@nuxt/image 会自动优化图片,转换格式 (如 webp), 调整大小等。
需要在 nuxt.config.ts 中配置允许的域名。
// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/image'],
  image: {
    domains: ['images.unsplash.com', 'cdn.example.com'],
    // 可以为特定域名设置别名
    alias: {
      unsplash: 'https://images.unsplash.com'
    }
  }
})
<template>
  <NuxtImg
    src="https://images.unsplash.com/photo-123"
    alt="Remote image"
    width="600"
    height="400"
    provider="ipx" <!-- Nuxt 内置的优化器,或配置其他如 Cloudinary, Vercel 等 -->
  />
  <!-- 使用别名 -->
  <NuxtImg src="/your-image-id" provider="unsplash" width="300" height="200" />
</template>
使用 preload 属性来提示浏览器优先加载关键图片 (如 LCP 元素)。
<template>
  <NuxtImg
    src="/hero-banner.jpg"
    alt="Hero Banner"
    width="1200"
    height="600"
    preload
  />
</template>
<NuxtPicture> 组件用于艺术指导,根据不同屏幕尺寸提供不同图片源。
<template>
  <NuxtPicture
    src="/image-large.png"
    :imgAttrs="{alt: 'My descriptive alt text'}"
    width="1000"
    height="500"
    :modifiers="{ resize: 'cover' }"
    :sizes="'xs:100vw sm:100vw md:100vw lg:1000px'"
    format="webp"
  />
</template>
Nuxt 3 没有像 Next.js 13 那样内置深度集成的 @next/font。常用的方法有:
在全局 CSS 文件 (如 assets/css/main.css) 或布局组件的 <style> 中使用 @font-face 或 @import。
/* assets/css/main.css */
/* 1. 使用 @font-face 引入本地字体文件 (放在 public/fonts/ 或 assets/fonts/) */
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-v12-latin-regular.woff2') format('woff2'),
       url('/fonts/inter-v12-latin-regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap; /* 推荐使用 swap */
}
@font-face {
  font-family: 'Inter';
  src: url('/fonts/inter-v12-latin-700.woff2') format('woff2'),
       url('/fonts/inter-v12-latin-700.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
/* 2. 或使用 @import 从 CDN 引入 (如 Google Fonts) */
/* @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap'); */
body {
  font-family: 'Inter', sans-serif;
}
确保在 nuxt.config.ts 中引入了 main.css。
@nuxtjs/google-fonts 模块安装模块: npm i -D @nuxtjs/google-fonts,然后在 nuxt.config.ts 中配置。
// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxtjs/google-fonts'
  ],
  googleFonts: {
    families: {
      // 字体名称: [字重列表] 或 true (默认字重) 或 配置对象
      Roboto: [100, 300, 400, 500, 700, 900],
      Inter: {
        wght: [100, 300, 400, 700],
        ital: [100] // 斜体
      },
      'Josefin+Sans': true, // 加号替换空格
    },
    display: 'swap', // 默认值 'swap'
    prefetch: true, // 预获取字体链接
    preconnect: true, // 预连接 Google Fonts
    // download: true, // !!!下载字体到本地并自托管 (推荐!)
    // useStylesheet: true // 使用 <link rel="stylesheet"> 代替 @import
    // base64: true // 如果 download 为 true, 可以内联 base64 字体 (不推荐,包体积大)
  }
})
该模块会自动处理字体的加载和优化,推荐开启 download: true 以获得最佳性能和隐私。
如果使用 @nuxtjs/tailwindcss 模块,可以在 tailwind.config.js 中配置字体。
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
  theme: {
    extend: {
      fontFamily: {
        // 假设已通过 @font-face 或 @nuxtjs/google-fonts 引入了 'Inter'
        sans: ['Inter', ...defaultTheme.fontFamily.sans],
      },
    },
  },
  // ... other config
}
useHead)Nuxt 3 使用 useHead 组合式函数来管理 <head> 标签,包括 <script>。
在页面组件的 <script setup> 中使用 useHead。
<template>
  <div>Dashboard Page</div>
</template>
<script setup>
useHead({
  script: [
    {
      src: 'https://example.com/dashboard-analytics.js',
      // defer: true, // 或 async: true
      // body: true // 将脚本放在 <body> 结束前,而不是 <head>
    }
  ]
})
</script>
在 nuxt.config.ts 的 app.head 中配置全局脚本。
// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: 'https://example.com/global-tracker.js',
          async: true,
          // body: true, // 推荐放 body 底部
        }
      ]
      // 也可以添加 link, meta, title 等
    }
  }
})
或者在 app.vue 或 默认布局 layouts/default.vue 中使用 useHead。
可以使用 innerHTML 或 children 属性添加内联脚本。
// nuxt.config.ts (全局示例)
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          // children 属性更安全,Nuxt 会处理转义
          children: `console.log('Inline script executed');`,
          // id: 'my-inline-script',
          // type: 'text/javascript'
        },
        /*
        {
          // 或者使用 innerHTML (需要注意 XSS 风险)
          innerHTML: `document.getElementById('banner').style.display = 'block';`,
          // body: true
        }
        */
      ]
    }
  }
})
在组件中使用 useHead:
<script setup>
useHead({
  script: [
    { children: `alert('Hello from inline script!');` }
  ]
})
</script>
useHead 目前不直接支持 onload 或 onerror 回调。如果需要,可以通过创建一个包装函数或使用第三方库(如 @vueuse/head 提供的更高级功能,但 Nuxt 的 useHead 通常足够)。对于简单场景,可以在 onMounted 中检查脚本是否加载(例如检查脚本定义的全局变量)。
<script setup>
import { onMounted } from 'vue'
useHead({
  script: [
    { src: 'https://example.com/library.js', id: 'lib-script' }
  ]
})
onMounted(() => {
  const script = document.getElementById('lib-script');
  if (script) {
    script.onload = () => {
      console.log('Library script loaded!');
      // 可以在这里调用库的函数
      // if (window.myLibrary) { window.myLibrary.init(); }
    };
    script.onerror = () => {
      console.error('Failed to load library script.');
    };
  }
  // 或者轮询检查脚本是否定义了某个全局变量
  /*
  const interval = setInterval(() => {
    if (window.myLibrary) {
      console.log('Library ready!');
      window.myLibrary.init();
      clearInterval(interval);
    }
  }, 100);
  */
})
</script>
Nuxt 3 推荐使用 @nuxtjs/eslint-module。
npx nuxi module add eslint --install
# 或者手动安装
# npm install --save-dev @nuxtjs/eslint-module eslint @nuxtjs/eslint-config-typescript
# yarn add --dev @nuxtjs/eslint-module eslint @nuxtjs/eslint-config-typescript
# pnpm add -D @nuxtjs/eslint-module eslint @nuxtjs/eslint-config-typescript
然后在 nuxt.config.ts 中添加模块:
// nuxt.config.ts
export default defineNuxtConfig({
  modules: [
    '@nuxtjs/eslint-module'
  ],
  // 可选配置
  eslint: {
    lintOnStart: false, // 不在开发服务器启动时检查 (推荐 false 以加快启动)
    // cache: false,
  }
})
在 package.json 中添加 lint 脚本:
"scripts": {
  "lint": "eslint .",
  "lint:fix": "eslint . --fix"
}
创建一个 .eslintrc.cjs (或 .js, .json) 配置文件:
// .eslintrc.cjs
module.exports = {
  root: true,
  extends: [
    'plugin:vue/vue3-essential', // Vue 3 基础规则
    '@nuxtjs/eslint-config-typescript' // Nuxt + TypeScript 推荐规则
    // 'prettier' // 如果使用 Prettier,确保这是最后一个 (见下文)
  ],
  parserOptions: {
    ecmaVersion: 'latest'
  },
  rules: {
    // 在这里覆盖或添加规则
    // "vue/multi-word-component-names": "off",
  }
}
运行 npm run lint 或 yarn lint 或 pnpm lint。
直接修改 .eslintrc.cjs 文件即可。
ESLint CLI 支持指定目录或文件:
# 只检查 components 和 composables 目录
eslint components composables
# 检查特定文件
eslint pages/index.vue utils/helpers.ts
可以在 package.json 中定义更具体的脚本。
在 .eslintrc.cjs 的 rules 部分添加规则并设置为 "off" 或 0。
// .eslintrc.cjs
module.exports = {
  // ...
  rules: {
    'vue/no-multiple-template-root': 'off', // 禁用 Vue 3 不再需要的规则
    '@typescript-eslint/no-unused-vars': ['warn', { 'argsIgnorePattern': '^_' }], // 未使用的变量警告(忽略下划线开头的)
  }
}
也可以使用行内注释禁用:
// eslint-disable-next-line no-console
console.log('临时允许 console.log');
安装 Prettier 和 ESLint 的集成插件:
npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier
# yarn add --dev prettier eslint-config-prettier eslint-plugin-prettier
# pnpm add -D prettier eslint-config-prettier eslint-plugin-prettier
在 .eslintrc.cjs 的 extends 数组末尾添加 'prettier' (禁用与 Prettier 冲突的规则) 或 'plugin:prettier/recommended' (应用 Prettier 规则并报告差异为 ESLint 错误)。
// .eslintrc.cjs (推荐方式)
module.exports = {
  root: true,
  extends: [
    'plugin:vue/vue3-essential',
    '@nuxtjs/eslint-config-typescript',
    'plugin:prettier/recommended' // 集成 Prettier
  ],
  // ...
}
创建 .prettierrc.js (或 .json, .yaml) 配置文件:
// .prettierrc.js
module.exports = {
  semi: false, // 不加分号
  singleQuote: true, // 使用单引号
  trailingComma: 'es5', // 尾随逗号
  printWidth: 100, // 行宽
  // ... 其他 Prettier 选项
};
结合 Husky 和 lint-staged 可以在 Git 提交前自动检查和修复暂存文件。
安装:
npm install --save-dev husky lint-staged
# yarn add --dev husky lint-staged
# pnpm add -D husky lint-staged
npx husky install
npm set-script prepare "husky install" # 或 yarn husky install
npx husky add .husky/pre-commit "npx lint-staged"
在 package.json 或 .lintstagedrc.js 中配置 lint-staged:
// package.json
{
  "lint-staged": {
    "*.{js,ts,vue}": "eslint --fix",
    "*.{css,scss,vue}": "prettier --write"
  }
}
// .lintstagedrc.js
module.exports = {
  '*.{js,ts,vue}': 'eslint --fix',
  '*.{css,scss,vue,json,md}': 'prettier --write',
}
Nuxt 3 是 TypeScript 优先的框架。
npx nuxi init <project-name> 默认创建的就是 TypeScript 项目,包含 tsconfig.json。
Nuxt 3 会自动生成类型 (.nuxt/nuxt.d.ts),提供自动导入、配置、API 的类型提示。
运行类型检查:
npx nuxi typecheck
# 或者
npm run typecheck # (如果 package.json 中定义了脚本)
useFetch 和 useAsyncData 支持泛型来指定返回数据的类型。
<script setup lang="ts">
interface Post {
  id: number;
  title: string;
  body: string;
}
// useFetch 的类型会自动从 API 响应推断 (如果 API 返回类型良好)
// 但显式指定更安全
const { data: post, pending, error } = await useFetch<Post>('/api/posts/1')
if (post.value) {
  console.log(post.value.title) // 类型安全
}
// useAsyncData 需要显式指定类型
const { data: posts } = await useAsyncData<Post[]>('postsList', () => $fetch('/api/posts'))
if (posts.value) {
  posts.value.forEach(p => console.log(p.id)); // 类型安全
}
// pick 选项也会影响类型
const { data: postTitle } = await useFetch('/api/posts/1', {
  pick: ['title'] // data 的类型会变成 Pick<Post, 'title'>
})
if (postTitle.value) {
  console.log(postTitle.value.title);
  // console.log(postTitle.value.id); // TS 报错,因为 id 没被 pick
}
// transform 选项改变类型
const { data: postLength } = await useFetch<Post>('/api/posts/1', {
  transform: (post): number => {
    return post.body.length;
  } // data 类型现在是 number | null
})
</script>
API 路由位于 server/api/ 目录下,使用 defineEventHandler。类型通常会自动推断。
// server/api/hello.ts
import type { IncomingMessage, ServerResponse } from 'http'
// defineEventHandler 会处理请求和响应对象,简化类型
export default defineEventHandler(event => {
  // event 对象包含 request, response 等信息
  // event.node.req (原生 Node 请求对象)
  // event.node.res (原生 Node 响应对象)
  // event.context (请求上下文,可以添加中间件信息)
  // 读取查询参数
  const query = getQuery(event) // { name: 'World' } for /api/hello?name=World
  const name = query.name || 'World'
  // 读取请求体 (需要异步)
  // const body = await readBody(event)
  // 设置 header
  // event.node.res.setHeader('Content-Type', 'application/json')
  // 返回值会被自动序列化 (通常是 JSON)
  return {
    message: `Hello, ${name}!`
  }
})
// 也可以定义更具体的返回类型
interface HelloResponse {
  message: string;
}
export default defineEventHandler<HelloResponse>(event => {
   // ...
   return { message: 'Hello' }
})
app.vue如果需要自定义 app.vue (不常见),它就是一个标准的 Vue 3 TypeScript 组件。
// app.vue
<template>
  <NuxtLayout>
    <NuxtPage /> <!-- 必须包含 NuxtPage -->
  </NuxtLayout>
</template>
<script setup lang="ts">
// 可以在这里添加全局逻辑或状态初始化
import { useHead } from '#imports' // Nuxt 自动导入
useHead({
  titleTemplate: (titleChunk) => {
    return titleChunk ? `${titleChunk} - My Nuxt App` : 'My Nuxt App';
  }
})
</script>
nuxt.config.tsdefineNuxtConfig 提供了完整的类型提示。
// nuxt.config.ts
import { defineNuxtConfig } from 'nuxt/config'
export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ['@nuxtjs/tailwindcss'],
  css: ['~/assets/css/main.css'],
  runtimeConfig: { // 运行时配置 (服务端可用)
    apiKey: 'default-secret-key', // process.env.NUXT_API_KEY 会覆盖
    public: { // 公开配置 (客户端和服务端都可用)
      baseUrl: '/api', // process.env.NUXT_PUBLIC_BASE_URL 会覆盖
    }
  },
  // ... 其他选项都有类型提示
})
可以在 nuxt.config.ts 中配置,但不推荐用于生产构建。
// nuxt.config.ts
export default defineNuxtConfig({
  typescript: {
    // 在构建时忽略 TS 错误
    // typeCheck: false, // (旧版本或特定场景)
    shim: false // 是否生成 shim 文件
    // 推荐: 使用 `npx nuxi typecheck` 单独检查类型
  },
})
Nuxt 3 默认从项目根目录的 .env 文件加载环境变量。
# .env
DB_HOST=localhost
DB_USER=myuser
DB_PASS=secretpassword
# 暴露给客户端的变量需要 NUXT_PUBLIC_ 前缀
NUXT_PUBLIC_GOOGLE_ANALYTICS_ID=UA-1234567-8
NUXT_PUBLIC_API_BASE_URL=/api
推荐使用 Runtime Config 来访问环境变量,它提供了类型安全和更好的管理。
在 nuxt.config.ts 中定义 runtimeConfig:
// nuxt.config.ts
export default defineNuxtConfig({
  runtimeConfig: {
    // 只在服务端可用的私有键 (默认从 .env 读取)
    dbUser: process.env.DB_USER, // 也可以直接赋值
    dbPassword: process.env.DB_PASS,
    // public 中的键在客户端和服务端都可用
    public: {
      gaId: process.env.NUXT_PUBLIC_GOOGLE_ANALYTICS_ID,
      apiBaseUrl: '/api' // 默认值
    }
  }
})
在应用中使用 useRuntimeConfig():
<script setup lang="ts">
const config = useRuntimeConfig()
// 在 <script setup> 或 setup() 中 (服务端和客户端)
console.log('API Base URL:', config.public.apiBaseUrl)
console.log('GA ID:', config.public.gaId)
// 只能在服务端访问私有键 (例如 API 路由、服务器插件)
// console.log('DB User:', config.dbUser) // 在客户端会是 undefined
// 如果在服务端代码中 (如 server/api/ or server/plugins/)
// 可以直接访问 config.dbUser
if (process.server) {
  console.log('DB User (server-side):', config.dbUser)
}
// 在 API 路由中使用
// server/api/my-endpoint.ts
export default defineEventHandler(() => {
  const config = useRuntimeConfig()
  console.log('Accessing DB User in API:', config.dbUser)
  return { status: 'ok' }
})
</script>
Vite (Nuxt 3 底层) 支持 .env 文件中的变量扩展,但行为可能与 Next.js 的 dotenv-expand 略有不同。通常建议避免复杂的变量扩展。
如果需要美元符号 $,通常不需要转义,但具体取决于上下文。
环境变量加载优先级:.env.production > .env.development > .env > 系统环境变量。 process.env 中的同名变量(如 NUXT_PUBLIC_API_BASE_URL)会覆盖 runtimeConfig 中的默认值。
Nuxt 根据 pages/ 目录结构自动生成 Vue Router 配置。
文件结构决定路由路径。
| :-- | -- | 
|---|---|
pages/index.vue | / | 
pages/about.vue | /about | 
pages/blog/index.vue | /blog | 
pages/blog/first-post.vue | /blog/first-post | 
pages/users/index.vue | /users | 
pages/users/profile.vue | /users/profile | 
使用方括号 [] 定义动态参数。
| :-- | -- | 
|---|---|
pages/users/[id].vue | /users/:id/users/123 | 
pages/posts/[slug].vue | /posts/:slug/posts/my-first-post | 
pages/products/[category]/[productId].vue | /products/:category/:productId/products/electronics/456 | 
pages/[username]/settings.vue | /:username/settings /john_doe/settings | 
在组件中访问路由参数:
// pages/users/[id].vue
<template>
  <div>User ID: {{ $route.params.id }}</div>
</template>
<script setup>
import { useRoute } from 'vue-router' // 或 Nuxt 自动导入的 useRoute
const route = useRoute()
const userId = computed(() => route.params.id) // 使用 computed 获取响应式参数
console.log('User ID from setup:', route.params.id);
</script>
使用带有三个点的方括号 [...]。
| :-- | -- | 
|---|---|
pages/articles/[...slug].vue | /articles/*/articles/a/b/c | 
参数值是一个数组。
// pages/articles/[...slug].vue
<template>
  <div>Article Slug Parts: {{ slugParts }}</div>
</template>
<script setup>
const route = useRoute()
// route.params.slug 会是 ['a', 'b', 'c'] 对于 /articles/a/b/c
const slugParts = computed(() => route.params.slug || [])
</script>
使用双方括号 [[...]]。这会匹配根路径以及之后的所有路径。
| :-- | -- | 
|---|---|
pages/optional/[[...slug]].vue | /optional/*/optional/optional/a/optional/a/b | 
/optional 时, route.params.slug 是 undefined。/optional/a 时, route.params.slug 是 ['a']。/optional/a/b 时, route.params.slug 是 ['a', 'b']。<NuxtLink>)使用 <NuxtLink> 组件进行内部导航。
<template>
  <nav>
    <ul>
      <li>
        <NuxtLink to="/">首页</NuxtLink>
      </li>
      <li>
        <NuxtLink to="/about">关于我们</NuxtLink>
      </li>
      <li>
        <!-- 链接到动态路由 -->
        <NuxtLink :to="`/users/${userId}`">我的主页</NuxtLink>
      </li>
      <li>
        <NuxtLink :to="{ name: 'posts-slug', params: { slug: postSlug } }">
          博文 (命名路由)
        </NuxtLink>
      </li>
      <li>
        <NuxtLink to="/external-page" external>外部链接</NuxtLink>
      </li>
    </ul>
  </nav>
</template>
<script setup>
const userId = ref(123)
const postSlug = ref('hello-nuxt')
// 可以通过 `npx nuxi routes` 查看生成的路由名称
// 例如 pages/posts/[slug].vue 的名称可能是 'posts-slug'
</script>
<style scoped>
/* NuxtLink 活动链接的默认 class */
.router-link-active {
  font-weight: bold;
}
/* NuxtLink 精确匹配活动链接的默认 class */
.router-link-exact-active {
  color: #41B883; /* Vue Green */
}
</style>
useRouter)使用 useRouter 获取 router 实例。
<template>
  <button @click="goToAbout">跳转到关于页</button>
  <button @click="goToPost('my-latest-post')">查看最新帖子</button>
</template>
<script setup>
import { useRouter } from 'vue-router' // 或 Nuxt 自动导入
const router = useRouter()
function goToAbout() {
  router.push('/about')
}
function goToPost(slug) {
  // 使用路径
  // router.push(`/posts/${slug}`)
  // 或使用命名路由和参数 (推荐)
  router.push({ name: 'posts-slug', params: { slug } })
}
</script>
definePageMeta)在页面组件中使用 definePageMeta 添加路由元信息,可用于中间件、布局等。
// pages/admin/index.vue
<script setup lang="ts">
definePageMeta({
  layout: 'admin', // 指定布局
  middleware: ['auth', 'admin-only'], // 应用中间件 (文件位于 middleware/ 目录下)
  // alias: ['/dashboard'], // 路由别名
  // keepalive: true, // 缓存页面状态
  // key: route => route.fullPath, // 自定义 key 用于 <NuxtPage :page-key="...">
  // transition: { name: 'fade', mode: 'out-in' } // 页面过渡效果
})
</script>
创建 middleware/auth.ts (或其他名称):
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const isLoggedIn = false // 实际应用中应检查用户登录状态
  if (!isLoggedIn && to.path !== '/login') {
    // console.log(`Redirecting from ${from.path} to /login (accessed ${to.path})`)
    return navigateTo('/login') // Nuxt 提供的重定向辅助函数
  }
  // 如果已登录或访问的是登录页,则继续导航
})
然后在 definePageMeta 或 nuxt.config.ts (全局中间件) 中应用。