跳到主要内容

目录结构✅

本主题涵盖 Nuxt 项目的目录结构约定,包括各个目录的作用、文件命名规范和组织方式。

Nuxt 项目的标准目录结构是什么样的?

答案

核心概念

Nuxt 采用约定优于配置的理念,通过标准化的目录结构来组织项目,减少配置复杂度,提高开发效率。

标准目录结构

nuxt-project/
├── .nuxt/ # Nuxt 构建输出目录(自动生成)
├── .output/ # 生产构建输出目录
├── assets/ # 需要构建处理的静态资源
├── components/ # Vue 组件(自动导入)
├── composables/ # 组合式函数(自动导入)
├── layouts/ # 布局组件
├── middleware/ # 路由中间件
├── pages/ # 页面组件(自动生成路由)
├── plugins/ # 插件
├── public/ # 静态资源(直接访问)
├── server/ # 服务端代码
│ ├── api/ # API 路由
│ ├── middleware/ # 服务端中间件
│ └── plugins/ # 服务端插件
├── stores/ # 状态管理(Pinia)
├── types/ # TypeScript 类型定义
├── utils/ # 工具函数(自动导入)
├── app.vue # 根组件
├── nuxt.config.ts # Nuxt 配置文件
├── package.json # 项目依赖
└── tailwind.config.js # Tailwind 配置(如果使用)

关键目录说明

  1. pages/ - 页面路由

    • 每个 .vue 文件自动生成一个路由
    • 支持嵌套路由和动态路由
  2. components/ - 组件库

    • 所有组件自动导入,无需手动 import
    • 支持嵌套目录结构
  3. layouts/ - 布局模板

    • 定义页面的整体布局结构
    • 页面可以选择使用不同的布局
  4. server/api/ - API 路由

    • 服务端 API 接口
    • 支持 RESTful 和 GraphQL
  5. middleware/ - 路由中间件

    • 在页面渲染前执行
    • 用于权限验证、重定向等

示例说明

<!-- pages/index.vue - 首页 -->
<template>
<div>
<h1>欢迎来到 Nuxt 应用</h1>
<UserCard :user="user" />
</div>
</template>

<script setup>
// components/UserCard.vue 自动导入,无需 import
const { data: user } = await $fetch('/api/user')
</script>
<!-- layouts/default.vue - 默认布局 -->
<template>
<div class="layout">
<header>
<nav>
<NuxtLink to="/">首页</NuxtLink>
<NuxtLink to="/about">关于</NuxtLink>
</nav>
</header>
<main>
<slot />
</main>
<footer>
<p>&copy; 2024 My App</p>
</footer>
</div>
</template>

面试官视角

该题考察候选人对 Nuxt 约定优于配置理念的理解,是 Nuxt 开发的基础知识。通过此题可以引出自动导入、路由生成等更深层的概念。

延伸阅读

pages 目录如何自动生成路由?

答案

核心概念

Nuxt 基于文件系统的路由,pages 目录中的每个 .vue 文件都会自动生成对应的路由,无需手动配置路由表。

路由生成规则

  1. 基础路由

    pages/index.vue          → /
    pages/about.vue → /about
    pages/contact.vue → /contact
  2. 嵌套路由

    pages/
    ├── index.vue → /
    ├── about.vue → /about
    └── products/
    ├── index.vue → /products
    └── detail.vue → /products/detail
  3. 动态路由

    pages/users/[id].vue     → /users/:id
    pages/posts/[slug].vue → /posts/:slug
  4. 嵌套动态路由

    pages/users/[id]/
    ├── index.vue → /users/:id
    ├── edit.vue → /users/:id/edit
    └── settings.vue → /users/:id/settings

实际示例

<!-- pages/users/[id].vue -->
<template>
<div>
<h1>用户详情</h1>
<p>用户ID: {{ $route.params.id }}</p>
<UserProfile :userId="$route.params.id" />
</div>
</template>

<script setup>
// 获取路由参数
const route = useRoute()
const userId = route.params.id

// 获取查询参数
const query = route.query
</script>
<!-- pages/blog/[...slug].vue - 捕获所有路由 -->
<template>
<div>
<h1>博客文章</h1>
<p>路径: {{ $route.params.slug.join('/') }}</p>
</div>
</template>

<script setup>
const route = useRoute()
// slug 是一个数组,包含所有路径段
const slug = route.params.slug
</script>

特殊文件

  1. index.vue - 目录的默认页面
  2. [...slug].vue - 捕获所有路由
  3. [...].vue - 捕获所有路由(包括空路径)

路由导航

<template>
<div>
<!-- 使用 NuxtLink 组件 -->
<NuxtLink to="/users/123">用户详情</NuxtLink>

<!-- 编程式导航 -->
<button @click="navigateToUser">跳转到用户页面</button>
</div>
</template>

<script setup>
const router = useRouter()

const navigateToUser = () => {
router.push('/users/123')
// 或者使用 navigateTo
await navigateTo('/users/123')
}
</script>

面试官视角

该题考察候选人对 Nuxt 文件系统路由的理解,是 Nuxt 开发的核心概念。通过此题可以引出动态路由、嵌套路由等更复杂的路由场景。

延伸阅读

layouts 目录的作用和使用方式?

答案

核心概念

Layouts 是 Nuxt 中用于定义页面整体布局结构的组件,允许在不同页面间共享相同的布局,提高代码复用性。

布局系统特点

  1. 自动应用:页面会自动使用默认布局
  2. 灵活切换:页面可以指定使用不同的布局
  3. 嵌套支持:布局可以嵌套使用
  4. 响应式:布局可以响应式适配不同设备

标准布局结构

<!-- layouts/default.vue - 默认布局 -->
<template>
<div class="default-layout">
<header class="header">
<nav class="nav">
<NuxtLink to="/" class="nav-link">首页</NuxtLink>
<NuxtLink to="/about" class="nav-link">关于</NuxtLink>
<NuxtLink to="/contact" class="nav-link">联系</NuxtLink>
</nav>
</header>

<main class="main">
<slot />
</main>

<footer class="footer">
<p>&copy; 2024 My App</p>
</footer>
</div>
</template>

<style scoped>
.default-layout {
min-height: 100vh;
display: flex;
flex-direction: column;
}

.main {
flex: 1;
padding: 2rem;
}
</style>

自定义布局

<!-- layouts/admin.vue - 管理后台布局 -->
<template>
<div class="admin-layout">
<aside class="sidebar">
<nav class="admin-nav">
<NuxtLink to="/admin/dashboard">仪表盘</NuxtLink>
<NuxtLink to="/admin/users">用户管理</NuxtLink>
<NuxtLink to="/admin/settings">系统设置</NuxtLink>
</nav>
</aside>

<main class="admin-main">
<header class="admin-header">
<h1>管理后台</h1>
<UserMenu />
</header>

<div class="admin-content">
<slot />
</div>
</main>
</div>
</template>

<style scoped>
.admin-layout {
display: flex;
min-height: 100vh;
}

.sidebar {
width: 250px;
background: #f5f5f5;
padding: 1rem;
}

.admin-main {
flex: 1;
display: flex;
flex-direction: column;
}

.admin-content {
flex: 1;
padding: 2rem;
}
</style>

页面使用布局

<!-- pages/about.vue - 使用默认布局 -->
<template>
<div>
<h1>关于我们</h1>
<p>这是关于页面,使用默认布局</p>
</div>
</template>
<!-- pages/admin/dashboard.vue - 使用自定义布局 -->
<template>
<div>
<h1>管理仪表盘</h1>
<div class="stats">
<div class="stat-card">总用户数: 1000</div>
<div class="stat-card">今日访问: 500</div>
</div>
</div>
</template>

<script setup>
// 指定使用 admin 布局
definePageMeta({
layout: 'admin'
})
</script>

布局切换

<!-- 动态切换布局 -->
<template>
<div>
<button @click="toggleLayout">切换布局</button>
<p>当前布局: {{ currentLayout }}</p>
</div>
</template>

<script setup>
const currentLayout = ref('default')

const toggleLayout = () => {
currentLayout.value = currentLayout.value === 'default' ? 'admin' : 'default'
setPageLayout(currentLayout.value)
}
</script>

布局错误处理

<!-- layouts/error.vue - 错误页面布局 -->
<template>
<div class="error-layout">
<div class="error-content">
<h1>{{ error.statusCode }}</h1>
<p>{{ error.statusMessage }}</p>
<NuxtLink to="/">返回首页</NuxtLink>
</div>
</div>
</template>

<script setup>
const props = defineProps({
error: Object
})
</script>

面试官视角

该题考察候选人对 Nuxt 布局系统的理解,是构建复杂应用的重要概念。通过此题可以引出页面元数据、错误处理等更深层的功能。

延伸阅读