第一个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>© {{ 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
九、总结 #
本章我们创建了一个完整的博客应用,学习了:
- 使用
NuxtLayout和NuxtPage构建布局 - 创建页面和动态路由
- 定义和使用组件
- 创建服务端 API
- 使用
useFetch获取数据 - 使用
useHead设置页面元信息 - 集成 Tailwind CSS
现在你已经掌握了 Nuxt.js 的基本用法,让我们继续深入学习更多功能。
最后更新:2026-03-28