✨Kevin‘s Blog🪐

Astro搭建自己的博客教学

📅发布日期:7/13/2025

第1课 astro-01-project-init.md

# 第 1 课:Astro 项目初始化 + 原理与结构

## 🚀 什么是 Astro?

Astro 是一个现代静态网站生成器(SSG),支持多框架集成(React、Vue、Svelte 等),以构建高性能、极简的静态网站和博客为目标。它默认生成纯静态页面,页面加载快、SEO 友好,且支持按需加载 JavaScript,避免不必要的前端负担。

相较于 Next.js、Nuxt 等,Astro 更专注静态内容生成,适合博客、文档和个人主页。

---

## 🚀 创建项目

打开终端,运行:

```bash
npm create astro@latest

选择模板时:

完成后进入项目目录:

cd my-blog
npm install
npm run dev

🧠 项目结构解读

my-blog/
├── public/          # 静态资源(图片、图标),直接拷贝到构建后的根目录
├── src/
   ├── pages/       # 页面文件夹,文件名对应网站路由(URL路径)
   ├── layouts/     # 页面模板,复用相同的页眉页脚等结构
   ├── components/  # 组件,封装可复用的小模块,如按钮、Callout等
├── astro.config.mjs # Astro 配置文件,定义构建、集成、路径等设置

目录说明


小结

本课你学会了:


进阶阅读

---

# 第2课 astro-02-content-collections.md

```md
# 第 2 课:写博客文章 + 内容集合原理

---

## 📁 什么是内容集合(Content Collections)?

Astro 通过内容集合管理博客文章、页面等内容,结合 [Zod](https://zod.dev) 进行数据结构验证,确保内容格式正确。

---

## 📁 创建内容集合目录

```bash
mkdir -p src/content/blog

创建示例文章 src/content/blog/2025-07-08.md

---
title: 我的第一篇博客
description: 从零开始学 Astro
pubDate: 2025-07-08
tags: ["astro"]
---

欢迎来到 Astro 博客!

注意:


🧪 配置内容集合 Schema(验证规则)

src/content/config.ts

import { defineCollection, z } from "astro:content";

const blog = defineCollection({
  schema: z.object({
    title: z.string(),
    description: z.string(),
    pubDate: z.date(),
    tags: z.array(z.string()).optional(),
  }),
});

export const collections = { blog };

为什么要 Schema?


📄 创建博客列表页 /blog

src/pages/blog.astro

---
import { getCollection } from "astro:content";
const posts = await getCollection("blog");
---

<ul>
  {posts.map(post => (
    <li><a href={`/blog/${post.slug}/`}>{post.data.title}</a></li>
  ))}
</ul>

原理说明


🧭 创建博客详情页 [...slug].astro

---
import { getCollection, getEntryBySlug } from "astro:content";
import { Markdown } from "astro/components";
import Layout from "../../layouts/Layout.astro";

export async function getStaticPaths() {
  const posts = await getCollection("blog");
  return posts.map(post => ({ params: { slug: post.slug.split("/") } }));
}

const slug = Astro.params.slug.join("/");
const post = await getEntryBySlug("blog", slug);
if (!post) throw new Error("文章不存在");
---

<Layout>
  <h1>{post.data.title}</h1>
  <Markdown content={post.body} />
</Layout>

原理说明


小结

本课你学会了:


进阶阅读

---

# 第3课 astro-03-notion-style-ui.md

```md
# 第 3 课:构建 Notion 风格博客 UI

---

## 🎨 设置全局样式

`src/styles/global.css`:

```css
:root {
  --bg: #fff;
  --fg: #111;
  --font-body: 'Noto Sans SC', sans-serif;
}

:root[data-theme="dark"] {
  --bg: #1e1e1e;
  --fg: #fff;
}

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font-body);
  padding: 2rem;
  max-width: 720px;
  margin: auto;
}

原理解释


💬 Callout 组件

src/components/Callout.astro

---
const { type = "info", icon = "💡" } = Astro.props;
---

<div class="callout {type}">
  <strong>{icon}</strong>
  <div><slot /></div>
</div>

<style>
.callout {
  padding: 1rem;
  border-left: 4px solid var(--fg);
  background: #f9f9f9;
  margin: 1.5rem 0;
  border-radius: 6px;
  display: flex;
  gap: 1rem;
}
</style>

原理解释


小结

本课你学会了:


进阶阅读

---

# 第4课 astro-04-dark-mode.md

```md
# 第 4 课:夜间模式实现 + 原理详解

---

## 🌙 CSS 变量控制颜色

```css
:root {
  --bg: #fff;
  --fg: #111;
}

:root[data-theme="dark"] {
  --bg: #1e1e1e;
  --fg: #fff;
}

原理说明


🌓 加入切换按钮

Layout.astro 中添加:

<button id="theme-toggle">🌓</button>

<script>
  const html = document.documentElement;
  // 页面加载时读取本地存储的主题设置,避免闪白
  const theme = localStorage.getItem("theme");
  if (theme === "dark") html.setAttribute("data-theme", "dark");

  // 点击切换按钮,切换主题,写入本地存储,保证刷新后保持
  document.getElementById("theme-toggle")?.addEventListener("click", () => {
    const isDark = html.getAttribute("data-theme") === "dark";
    if (isDark) {
      html.removeAttribute("data-theme");
      localStorage.setItem("theme", "light");
    } else {
      html.setAttribute("data-theme", "dark");
      localStorage.setItem("theme", "dark");
    }
  });
</script>

原理说明


小结

本课你学会了:


进阶阅读

---

以上4个文件,内容细化并且涵盖你提到“写错”的地方也已修正。  
你需要我帮你生成这些文件的真实文件到你的项目目录?还是导出为 ZIP 下载包?