第一个Nuxt.js应用 #

一、应用概述 #

我们将创建一个简单的博客应用,包含以下功能:

  • 首页展示文章列表
  • 文章详情页
  • 关于页面
  • 响应式布局

通过这个项目,你将学习到:

  • 页面创建和路由
  • 组件定义和使用
  • 数据获取
  • 布局系统
  • 样式处理

二、创建项目 #

2.1 初始化项目 #

bash
npx nuxi@latest init my-blog
cd my-blog
pnpm install

2.2 项目结构 #

创建以下目录结构:

text
my-blog/
├── app.vue
├── nuxt.config.ts
├── pages/
│   ├── index.vue
│   ├── about.vue
│   └── blog/
│       ├── index.vue
│       └── [id].vue
├── components/
│   ├── AppHeader.vue
│   ├── AppFooter.vue
│   └── BlogCard.vue
├── layouts/
│   └── default.vue
├── composables/
│   └── useBlog.ts
└── server/
    └── api/
        └── blog/
            ├── index.ts
            └── [id].ts

三、创建布局 #

3.1 默认布局 #

创建 layouts/default.vue

vue
<template>
  <div class="min-h-screen flex flex-col">
    <AppHeader />
    <main class="flex-1">
      <slot />
    </main>
    <AppFooter />
  </div>
</template>

<script setup lang="ts">
</script>

3.2 头部组件 #

创建 components/AppHeader.vue

vue
<template>
  <header class="bg-blue-600 text-white">
    <nav class="container mx-auto px-4 py-4">
      <div class="flex items-center justify-between">
        <NuxtLink to="/" class="text-xl font-bold">
          My Blog
        </NuxtLink>
        <ul class="flex space-x-6">
          <li>
            <NuxtLink to="/" class="hover:text-blue-200 transition">
              首页
            </NuxtLink>
          </li>
          <li>
            <NuxtLink to="/blog" class="hover:text-blue-200 transition">
              博客
            </NuxtLink>
          </li>
          <li>
            <NuxtLink to="/about" class="hover:text-blue-200 transition">
              关于
            </NuxtLink>
          </li>
        </ul>
      </div>
    </nav>
  </header>
</template>

<script setup lang="ts">
</script>

3.3 底部组件 #

创建 components/AppFooter.vue

vue
<template>
  <footer class="bg-gray-800 text-white py-8">
    <div class="container mx-auto px-4 text-center">
      <p>&copy; {{ new Date().getFullYear() }} My Blog. All rights reserved.</p>
    </div>
  </footer>
</template>

<script setup lang="ts">
</script>

四、创建页面 #

4.1 应用入口 #

修改 app.vue

vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
</template>

4.2 首页 #

创建 pages/index.vue

vue
<template>
  <div class="container mx-auto px-4 py-8">
    <section class="text-center mb-12">
      <h1 class="text-4xl font-bold mb-4">欢迎来到我的博客</h1>
      <p class="text-gray-600 text-lg">分享技术,记录生活</p>
    </section>
    
    <section>
      <h2 class="text-2xl font-bold mb-6">最新文章</h2>
      <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
        <BlogCard
          v-for="post in posts"
          :key="post.id"
          :post="post"
        />
      </div>
    </section>
  </div>
</template>

<script setup lang="ts">
interface Post {
  id: number
  title: string
  excerpt: string
  date: string
}

const { data: posts } = await useFetch<Post[]>('/api/blog')
</script>

4.3 博客列表页 #

创建 pages/blog/index.vue

vue
<template>
  <div class="container mx-auto px-4 py-8">
    <h1 class="text-3xl font-bold mb-8">全部文章</h1>
    <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
      <BlogCard
        v-for="post in posts"
        :key="post.id"
        :post="post"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
interface Post {
  id: number
  title: string
  excerpt: string
  date: string
}

const { data: posts } = await useFetch<Post[]>('/api/blog')

useHead({
  title: '博客文章 - My Blog'
})
</script>

4.4 博客详情页 #

创建 pages/blog/[id].vue

vue
<template>
  <div class="container mx-auto px-4 py-8">
    <article v-if="post" class="max-w-3xl mx-auto">
      <header class="mb-8">
        <h1 class="text-4xl font-bold mb-4">{{ post.title }}</h1>
        <p class="text-gray-500">{{ post.date }}</p>
      </header>
      <div class="prose prose-lg">
        <p>{{ post.content }}</p>
      </div>
      <footer class="mt-8">
        <NuxtLink to="/blog" class="text-blue-600 hover:underline">
          ← 返回文章列表
        </NuxtLink>
      </footer>
    </article>
    <div v-else class="text-center py-12">
      <p class="text-gray-500">文章不存在</p>
      <NuxtLink to="/blog" class="text-blue-600 hover:underline">
        返回文章列表
      </NuxtLink>
    </div>
  </div>
</template>

<script setup lang="ts">
interface Post {
  id: number
  title: string
  content: string
  date: string
}

const route = useRoute()
const { data: post } = await useFetch<Post>(`/api/blog/${route.params.id}`)

useHead({
  title: post.value ? `${post.value.title} - My Blog` : '文章不存在'
})
</script>

4.5 关于页面 #

创建 pages/about.vue

vue
<template>
  <div class="container mx-auto px-4 py-8">
    <div class="max-w-2xl mx-auto">
      <h1 class="text-4xl font-bold mb-6">关于我</h1>
      <div class="prose prose-lg">
        <p>
          你好!我是一名热爱技术的开发者,这个博客是我的个人空间,
          用于分享技术文章和生活感悟。
        </p>
        <h2>技术栈</h2>
        <ul>
          <li>前端:Vue.js, Nuxt.js, TypeScript</li>
          <li>后端:Node.js, Python</li>
          <li>数据库:PostgreSQL, MongoDB</li>
        </ul>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
useHead({
  title: '关于 - My Blog'
})
</script>

五、创建组件 #

5.1 博客卡片组件 #

创建 components/BlogCard.vue

vue
<template>
  <NuxtLink :to="`/blog/${post.id}`" class="block">
    <article class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition">
      <div class="p-6">
        <h3 class="text-xl font-bold mb-2">{{ post.title }}</h3>
        <p class="text-gray-600 mb-4">{{ post.excerpt }}</p>
        <p class="text-sm text-gray-400">{{ post.date }}</p>
      </div>
    </article>
  </NuxtLink>
</template>

<script setup lang="ts">
interface Post {
  id: number
  title: string
  excerpt: string
  date: string
}

defineProps<{
  post: Post
}>()
</script>

六、创建API #

6.1 模拟数据 #

创建 server/api/blog/index.ts

typescript
interface Post {
  id: number
  title: string
  excerpt: string
  date: string
}

const posts: Post[] = [
  {
    id: 1,
    title: 'Nuxt.js 入门指南',
    excerpt: '本文将介绍 Nuxt.js 的基本概念和使用方法...',
    date: '2024-01-15'
  },
  {
    id: 2,
    title: 'Vue 3 组合式 API 详解',
    excerpt: '深入了解 Vue 3 的组合式 API,提升开发效率...',
    date: '2024-01-10'
  },
  {
    id: 3,
    title: 'TypeScript 最佳实践',
    excerpt: '分享 TypeScript 开发中的最佳实践和技巧...',
    date: '2024-01-05'
  }
]

export default defineEventHandler(() => {
  return posts
})

6.2 文章详情API #

创建 server/api/blog/[id].ts

typescript
interface Post {
  id: number
  title: string
  excerpt: string
  content: string
  date: string
}

const posts: Post[] = [
  {
    id: 1,
    title: 'Nuxt.js 入门指南',
    excerpt: '本文将介绍 Nuxt.js 的基本概念和使用方法...',
    content: 'Nuxt.js 是一个基于 Vue.js 的全栈框架,它提供了服务端渲染、静态站点生成等功能。本文将从安装配置开始,逐步介绍 Nuxt.js 的核心概念和最佳实践...',
    date: '2024-01-15'
  },
  {
    id: 2,
    title: 'Vue 3 组合式 API 详解',
    excerpt: '深入了解 Vue 3 的组合式 API,提升开发效率...',
    content: 'Vue 3 引入了组合式 API,这是一种全新的组织组件逻辑的方式。相比选项式 API,组合式 API 提供了更好的代码复用和类型推断能力...',
    date: '2024-01-10'
  },
  {
    id: 3,
    title: 'TypeScript 最佳实践',
    excerpt: '分享 TypeScript 开发中的最佳实践和技巧...',
    content: 'TypeScript 为 JavaScript 添加了静态类型检查,大大提升了代码质量和开发体验。本文将分享一些 TypeScript 开发中的最佳实践...',
    date: '2024-01-05'
  }
]

export default defineEventHandler((event) => {
  const id = parseInt(getRouterParam(event, 'id') || '0')
  return posts.find(post => post.id === id) || null
})

七、添加样式 #

7.1 安装 Tailwind CSS #

bash
pnpm add -D @nuxtjs/tailwindcss

7.2 配置 Nuxt #

修改 nuxt.config.ts

typescript
export default defineNuxtConfig({
  devtools: { enabled: true },
  modules: ['@nuxtjs/tailwindcss']
})

7.3 Tailwind 配置 #

创建 tailwind.config.js

javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './components/**/*.{js,vue,ts}',
    './layouts/**/*.vue',
    './pages/**/*.vue',
    './plugins/**/*.{js,ts}',
    './app.vue'
  ],
  theme: {
    extend: {}
  },
  plugins: []
}

八、运行项目 #

8.1 启动开发服务器 #

bash
pnpm dev

访问 http://localhost:3000 查看应用。

8.2 构建生产版本 #

bash
pnpm build

8.3 预览生产版本 #

bash
pnpm preview

九、总结 #

本章我们创建了一个完整的博客应用,学习了:

  • 使用 NuxtLayoutNuxtPage 构建布局
  • 创建页面和动态路由
  • 定义和使用组件
  • 创建服务端 API
  • 使用 useFetch 获取数据
  • 使用 useHead 设置页面元信息
  • 集成 Tailwind CSS

现在你已经掌握了 Nuxt.js 的基本用法,让我们继续深入学习更多功能。

最后更新:2026-03-28