Nuxt.js

目录约定与自动导入

掌握 Nuxt 的目录约定和自动导入机制,理解每个目录的作用,减少不必要的 import 代码。

🎯 引言

学会这篇文章,你能搞清楚 Nuxt 项目里各个目录分别是干什么的,为什么很多组件和函数可以“不写 import 就能用”。你还会知道什么时候该依赖自动导入,什么时候最好显式 import,让项目既简洁又不容易出错。


🧱 Nuxt 的目录约定

Nuxt 采用“约定优于配置”的思想:只要文件放在正确的目录下,框架就会自动识别并赋予它相应的职责。你不需要像纯 Vite 项目那样手动注册路由、组件或插件。

一个典型的 Nuxt 项目目录如下:

my-nuxt-app/
├─ app/
│  ├─ app.vue          // 应用入口
│  ├─ pages/           // 页面路由
│  ├─ components/      // 自动导入的组件
│  ├─ composables/     // 自动导入的组合式函数
│  ├─ utils/           // 自动导入的工具函数
│  ├─ layouts/         // 布局
│  ├─ middleware/      // 路由中间件
│  ├─ plugins/         // 插件
├─ public/             // 静态资源
├─ server/             // 服务端 API
├─ nuxt.config.ts      // 配置文件
├─ package.json

下面重点讲最常用的几个目录。


📁 app.vue:应用入口

Nuxt 3 项目的根组件是 app/app.vue,相当于普通 Vue 项目的 src/App.vue

app/app.vue
<template>
    <div>
        <NuxtPage />
    </div>
</template>

<NuxtPage /> 是 Nuxt 内置组件,用来渲染当前路由匹配的页面。如果你把它去掉,pages/ 下的页面就不会显示。

如果项目很简单,只有 app.vue 没有 pages/,那它就是一个单页面应用,和用 Vite 写的 Vue 项目差不多。

📁 pages/:文件即路由

pages/ 目录下创建 .vue 文件,Nuxt 会自动把它注册为路由。

pages/
├─ index.vue      // 对应 /
├─ about.vue      // 对应 /about
├─ user/
│  ├─ index.vue   // 对应 /user
│  ├─ [id].vue    // 对应 /user/:id
文件路由我们会在下一篇文章详细展开,这里先记住:Nuxt 看到 pages/ 就会帮你生成 vue-router 配置。

📁 components/:组件自动导入

普通 Vue 项目需要在每个页面里手动 import 组件:

<script setup>
import MyButton from '../components/MyButton.vue';
</script>

在 Nuxt 里,只要组件放在 app/components/ 目录下,就可以直接在模板里使用,不需要 import

app/pages/index.vue
<template>
    <div>
        <MyButton>点我</MyButton>
    </div>
</template>
自动导入只识别 app/components/ 下的组件。如果你把组件放在别的目录,仍然需要手动 import。

📁 composables/:组合式函数自动导入

在 Vue3 项目里,我们习惯把可复用的逻辑写成组合式函数。在 Nuxt 里,只要放在 app/composables/ 目录下,就可以在所有组件中直接使用。

app/composables/useCounter.js
export function useCounter() {
    const count = ref(0);
    const add = () => count.value++;

    return {
        count,
        add,
    };
}

在页面中直接使用:

app/pages/index.vue
<template>
    <p>计数:{{ count }}</p>
    <button @click="add">加一</button>
</template>

<script setup>
const { count, add } = useCounter();
</script>
组合式函数建议以 use 开头命名,例如 useUseruseFetchData,这是社区约定,也能和 Nuxt 内置的 useFetchuseRoute 等保持一致。

📁 utils/:工具函数自动导入

一些不依赖 Vue 响应式系统的纯工具函数,可以放在 app/utils/ 目录下,同样会自动导入。

app/utils/formatDate.js
export function formatDate(date) {
    return new Date(date).toLocaleDateString();
}

在组件或 composable 中直接使用:

app/pages/index.vue
<template>
    <p>今天:{{ formatDate(new Date()) }}</p>
</template>

📁 public/assets/ 的区别

Nuxt 里放静态资源有两个常见位置,容易混淆:

目录用途访问方式
public/不需要打包处理的文件,如 favicon.ico、图片、字体直接通过 /文件名 访问
assets/需要经过构建工具处理的文件,如 Sass、需要压缩的图片通过 ~/assets/xxx 引入

举例:把 logo.png 放到 public/logo.png,在页面里直接写:

<template>
    <img src="/logo.png" alt="logo" />
</template>
不要把需要版本控制或构建处理的资源放在 public/,否则不会经过 Nuxt 的构建优化。

🧰 自动导入的本质

自动导入不是魔法,而是 Nuxt 在启动时扫描了 components/composables/utils/ 等目录,然后生成了一份“名称到文件路径”的映射表。开发时你 seemingly 没写 import,实际上构建工具已经帮你补上了。

虽然自动导入很爽,但在某些场景下建议显式 import:
  • 函数名容易冲突时。
  • 写单测或库代码时,自动导入可能不生效。
  • 团队规范要求代码可读性优先时。

🧾 小节总结

  • Nuxt 采用约定优于配置的目录结构,app/ 下不同目录有不同职责。
  • app/app.vue 是应用入口,必须用 <NuxtPage /> 渲染页面。
  • pages/ 下的文件会自动生成路由,components/composables/utils/ 下的内容会自动导入。
  • public/ 放不需要构建处理的静态资源,assets/ 放需要构建处理的资源。
  • 自动导入能大幅减少样板代码,但在冲突或测试场景下建议显式 import。

❓ 知识问答

Q1:组件放在 app/components/ 的子目录里还能自动导入吗?

可以。Nuxt 会递归扫描 components/ 下的所有 .vue 文件,组件名就是文件名。

Q2:composables/utils/ 有什么区别?

composables/ 适合放和 Vue 响应式相关的逻辑(会用到 refcomputed 等);utils/ 适合放纯函数工具(不依赖 Vue)。

Q3:自动导入在生产环境也有效吗?

有效。自动导入是 Nuxt 构建流程的一部分,开发环境和生产环境都会生效。

Q4:我不想用自动导入,可以关闭吗?

可以在 nuxt.config.ts 中配置 components: falseimports: { autoImport: false },但通常不建议关闭。


🧪 小练习

在已有的 Nuxt 项目中完成以下操作:

  1. app/components/ 下创建一个 AppAlert.vue 组件,显示一段提示文字。
  2. app/composables/ 下创建一个 useCounter.js,返回 countadd
  3. app/utils/ 下创建一个 formatPrice.js,把数字格式化成 ¥xx.xx
  4. app/pages/index.vue 中直接使用这三个自动导入的内容,不需要写任何 import
app/pages/index.vue
<template>
    <div>
        <AppAlert />
        <p>价格:{{ formatPrice(19.9) }}</p>
        <p>计数:{{ count }}</p>
        <button @click="add">加一</button>
    </div>
</template>

<script setup>
// 请在这里使用自动导入的 useCounter,不需要 import
</script>

🎉 恭喜你已经掌握了 Nuxt 的目录约定和自动导入机制!下一篇我们会学习 Nuxt 的文件路由系统,理解页面跳转和动态参数。