目录约定与自动导入
🎯 引言
学会这篇文章,你能搞清楚 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。
<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
pages/ 就会帮你生成 vue-router 配置。📁 components/:组件自动导入
普通 Vue 项目需要在每个页面里手动 import 组件:
<script setup>
import MyButton from '../components/MyButton.vue';
</script>
在 Nuxt 里,只要组件放在 app/components/ 目录下,就可以直接在模板里使用,不需要 import。
<template>
<div>
<MyButton>点我</MyButton>
</div>
</template>
app/components/ 下的组件。如果你把组件放在别的目录,仍然需要手动 import。📁 composables/:组合式函数自动导入
在 Vue3 项目里,我们习惯把可复用的逻辑写成组合式函数。在 Nuxt 里,只要放在 app/composables/ 目录下,就可以在所有组件中直接使用。
export function useCounter() {
const count = ref(0);
const add = () => count.value++;
return {
count,
add,
};
}
在页面中直接使用:
<template>
<p>计数:{{ count }}</p>
<button @click="add">加一</button>
</template>
<script setup>
const { count, add } = useCounter();
</script>
use 开头命名,例如 useUser、useFetchData,这是社区约定,也能和 Nuxt 内置的 useFetch、useRoute 等保持一致。📁 utils/:工具函数自动导入
一些不依赖 Vue 响应式系统的纯工具函数,可以放在 app/utils/ 目录下,同样会自动导入。
export function formatDate(date) {
return new Date(date).toLocaleDateString();
}
在组件或 composable 中直接使用:
<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,实际上构建工具已经帮你补上了。
- 函数名容易冲突时。
- 写单测或库代码时,自动导入可能不生效。
- 团队规范要求代码可读性优先时。
🧾 小节总结
- Nuxt 采用约定优于配置的目录结构,
app/下不同目录有不同职责。 app/app.vue是应用入口,必须用<NuxtPage />渲染页面。pages/下的文件会自动生成路由,components/、composables/、utils/下的内容会自动导入。public/放不需要构建处理的静态资源,assets/放需要构建处理的资源。- 自动导入能大幅减少样板代码,但在冲突或测试场景下建议显式 import。
❓ 知识问答
Q1:组件放在 app/components/ 的子目录里还能自动导入吗?
可以。Nuxt 会递归扫描 components/ 下的所有 .vue 文件,组件名就是文件名。
Q2:composables/ 和 utils/ 有什么区别?
composables/ 适合放和 Vue 响应式相关的逻辑(会用到 ref、computed 等);utils/ 适合放纯函数工具(不依赖 Vue)。
Q3:自动导入在生产环境也有效吗?
有效。自动导入是 Nuxt 构建流程的一部分,开发环境和生产环境都会生效。
Q4:我不想用自动导入,可以关闭吗?
可以在 nuxt.config.ts 中配置 components: false 或 imports: { autoImport: false },但通常不建议关闭。
🧪 小练习
在已有的 Nuxt 项目中完成以下操作:
- 在
app/components/下创建一个AppAlert.vue组件,显示一段提示文字。 - 在
app/composables/下创建一个useCounter.js,返回count和add。 - 在
app/utils/下创建一个formatPrice.js,把数字格式化成¥xx.xx。 - 在
app/pages/index.vue中直接使用这三个自动导入的内容,不需要写任何import。
<template>
<div>
<AppAlert />
<p>价格:{{ formatPrice(19.9) }}</p>
<p>计数:{{ count }}</p>
<button @click="add">加一</button>
</div>
</template>
<script setup>
// 请在这里使用自动导入的 useCounter,不需要 import
</script>
🎉 恭喜你已经掌握了 Nuxt 的目录约定和自动导入机制!下一篇我们会学习 Nuxt 的文件路由系统,理解页面跳转和动态参数。
