第一个项目 #

一、项目概述 #

我们将创建一个简单的个人主页项目,包含以下功能:

  • 首页展示个人信息
  • 关于页面
  • 项目展示页面
  • 响应式导航栏

项目预览 #

text
┌─────────────────────────────────────────────────────┐
│                    我的主页                          │
├─────────────────────────────────────────────────────┤
│  [首页] [关于] [项目]                    个人主页    │
├─────────────────────────────────────────────────────┤
│                                                     │
│              你好,我是开发者                        │
│           欢迎来到我的个人主页                       │
│                                                     │
│              [了解更多] [查看项目]                   │
│                                                     │
└─────────────────────────────────────────────────────┘

二、创建项目 #

2.1 初始化项目 #

bash
# 创建项目
npm create astro@latest my-portfolio

# 进入项目目录
cd my-portfolio

# 启动开发服务器
npm run dev

2.2 项目结构 #

创建以下目录结构:

text
my-portfolio/
├── public/
│   └── favicon.svg
├── src/
│   ├── components/
│   │   ├── Header.astro
│   │   ├── Footer.astro
│   │   └── Hero.astro
│   ├── layouts/
│   │   └── Layout.astro
│   ├── pages/
│   │   ├── index.astro
│   │   ├── about.astro
│   │   └── projects.astro
│   └── styles/
│       └── global.css
├── astro.config.mjs
└── package.json

三、创建布局组件 #

3.1 基础布局 #

创建 src/layouts/Layout.astro

astro
---
interface Props {
  title: string;
}

const { title } = Astro.props;
---

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="我的个人主页" />
    <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
    <title>{title}</title>
  </head>
  <body>
    <slot />
  </body>
</html>

<style is:global>
  * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
  }

  body {
    font-family: system-ui, -apple-system, sans-serif;
    line-height: 1.6;
    color: #333;
  }

  a {
    color: inherit;
    text-decoration: none;
  }
</style>

四、创建通用组件 #

4.1 导航头部 #

创建 src/components/Header.astro

astro
---
const navItems = [
  { label: '首页', href: '/' },
  { label: '关于', href: '/about' },
  { label: '项目', href: '/projects' },
];
---

<header class="header">
  <nav class="nav">
    <a href="/" class="logo">我的主页</a>
    <ul class="nav-list">
      {navItems.map((item) => (
        <li>
          <a href={item.href} class="nav-link">
            {item.label}
          </a>
        </li>
      ))}
    </ul>
  </nav>
</header>

<style>
  .header {
    background: #fff;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    position: sticky;
    top: 0;
    z-index: 100;
  }

  .nav {
    max-width: 1200px;
    margin: 0 auto;
    padding: 1rem 2rem;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .logo {
    font-size: 1.5rem;
    font-weight: bold;
    color: #2563eb;
  }

  .nav-list {
    display: flex;
    list-style: none;
    gap: 2rem;
  }

  .nav-link {
    padding: 0.5rem 1rem;
    border-radius: 4px;
    transition: background-color 0.2s;
  }

  .nav-link:hover {
    background-color: #f3f4f6;
  }
</style>

4.2 页脚组件 #

创建 src/components/Footer.astro

astro
---
const year = new Date().getFullYear();
---

<footer class="footer">
  <div class="footer-content">
    <p>&copy; {year} 我的主页. 保留所有权利.</p>
    <div class="social-links">
      <a href="https://github.com" target="_blank" rel="noopener">GitHub</a>
      <a href="https://twitter.com" target="_blank" rel="noopener">Twitter</a>
    </div>
  </div>
</footer>

<style>
  .footer {
    background: #f3f4f6;
    padding: 2rem;
    margin-top: auto;
  }

  .footer-content {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    justify-content: space-between;
    align-items: center;
  }

  .social-links {
    display: flex;
    gap: 1rem;
  }

  .social-links a {
    color: #6b7280;
    transition: color 0.2s;
  }

  .social-links a:hover {
    color: #2563eb;
  }
</style>

4.3 Hero 组件 #

创建 src/components/Hero.astro

astro
---
interface Props {
  title: string;
  subtitle: string;
}

const { title, subtitle } = Astro.props;
---

<section class="hero">
  <div class="hero-content">
    <h1 class="hero-title">{title}</h1>
    <p class="hero-subtitle">{subtitle}</p>
    <div class="hero-actions">
      <a href="/about" class="btn btn-primary">了解更多</a>
      <a href="/projects" class="btn btn-secondary">查看项目</a>
    </div>
  </div>
</section>

<style>
  .hero {
    min-height: 80vh;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    color: #fff;
  }

  .hero-content {
    max-width: 800px;
    padding: 2rem;
  }

  .hero-title {
    font-size: 3rem;
    margin-bottom: 1rem;
  }

  .hero-subtitle {
    font-size: 1.25rem;
    opacity: 0.9;
    margin-bottom: 2rem;
  }

  .hero-actions {
    display: flex;
    gap: 1rem;
    justify-content: center;
  }

  .btn {
    padding: 0.75rem 1.5rem;
    border-radius: 8px;
    font-weight: 500;
    transition: transform 0.2s, box-shadow 0.2s;
  }

  .btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
  }

  .btn-primary {
    background: #fff;
    color: #2563eb;
  }

  .btn-secondary {
    background: transparent;
    border: 2px solid #fff;
    color: #fff;
  }
</style>

五、创建页面 #

5.1 首页 #

创建 src/pages/index.astro

astro
---
import Layout from '../layouts/Layout.astro';
import Header from '../components/Header.astro';
import Hero from '../components/Hero.astro';
import Footer from '../components/Footer.astro';
---

<Layout title="首页 - 我的主页">
  <Header />
  <main>
    <Hero 
      title="你好,我是开发者" 
      subtitle="欢迎来到我的个人主页,这里展示我的作品和技能" 
    />
    
    <section class="features">
      <div class="container">
        <h2>我的技能</h2>
        <div class="feature-grid">
          <div class="feature-card">
            <h3>前端开发</h3>
            <p>精通 HTML、CSS、JavaScript,熟悉 React、Vue 等框架</p>
          </div>
          <div class="feature-card">
            <h3>后端开发</h3>
            <p>熟悉 Node.js、Python,有丰富的 API 开发经验</p>
          </div>
          <div class="feature-card">
            <h3>全栈开发</h3>
            <p>能够独立完成从前端到后端的完整项目开发</p>
          </div>
        </div>
      </div>
    </section>
  </main>
  <Footer />
</Layout>

<style>
  main {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
  }

  .features {
    padding: 4rem 2rem;
    background: #f9fafb;
  }

  .container {
    max-width: 1200px;
    margin: 0 auto;
  }

  .features h2 {
    text-align: center;
    font-size: 2rem;
    margin-bottom: 2rem;
  }

  .feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 2rem;
  }

  .feature-card {
    background: #fff;
    padding: 2rem;
    border-radius: 12px;
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  }

  .feature-card h3 {
    color: #2563eb;
    margin-bottom: 1rem;
  }
</style>

5.2 关于页面 #

创建 src/pages/about.astro

astro
---
import Layout from '../layouts/Layout.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';

const skills = [
  { name: 'JavaScript', level: 90 },
  { name: 'TypeScript', level: 85 },
  { name: 'React', level: 88 },
  { name: 'Vue', level: 80 },
  { name: 'Node.js', level: 75 },
  { name: 'Python', level: 70 },
];
---

<Layout title="关于 - 我的主页">
  <Header />
  <main class="main">
    <section class="about-section">
      <div class="container">
        <h1>关于我</h1>
        <div class="about-content">
          <div class="about-text">
            <p>
              我是一名热爱编程的全栈开发者,拥有多年的 Web 开发经验。
              我热衷于学习新技术,并将其应用到实际项目中。
            </p>
            <p>
              在工作中,我注重代码质量和用户体验,致力于创建高性能、
              易维护的应用程序。
            </p>
          </div>
          
          <div class="skills">
            <h2>技能水平</h2>
            {skills.map((skill) => (
              <div class="skill-item">
                <div class="skill-header">
                  <span class="skill-name">{skill.name}</span>
                  <span class="skill-level">{skill.level}%</span>
                </div>
                <div class="skill-bar">
                  <div 
                    class="skill-progress" 
                    style={`width: ${skill.level}%`}
                  ></div>
                </div>
              </div>
            ))}
          </div>
        </div>
      </div>
    </section>
  </main>
  <Footer />
</Layout>

<style>
  .main {
    min-height: 100vh;
    padding-top: 80px;
  }

  .about-section {
    padding: 4rem 2rem;
  }

  .container {
    max-width: 1000px;
    margin: 0 auto;
  }

  h1 {
    font-size: 2.5rem;
    margin-bottom: 2rem;
    color: #1f2937;
  }

  .about-content {
    display: grid;
    gap: 3rem;
  }

  .about-text p {
    font-size: 1.1rem;
    line-height: 1.8;
    color: #4b5563;
    margin-bottom: 1rem;
  }

  .skills h2 {
    font-size: 1.5rem;
    margin-bottom: 1.5rem;
    color: #1f2937;
  }

  .skill-item {
    margin-bottom: 1rem;
  }

  .skill-header {
    display: flex;
    justify-content: space-between;
    margin-bottom: 0.5rem;
  }

  .skill-name {
    font-weight: 500;
  }

  .skill-level {
    color: #6b7280;
  }

  .skill-bar {
    height: 8px;
    background: #e5e7eb;
    border-radius: 4px;
    overflow: hidden;
  }

  .skill-progress {
    height: 100%;
    background: linear-gradient(90deg, #2563eb, #7c3aed);
    border-radius: 4px;
    transition: width 0.5s ease;
  }
</style>

5.3 项目页面 #

创建 src/pages/projects.astro

astro
---
import Layout from '../layouts/Layout.astro';
import Header from '../components/Header.astro';
import Footer from '../components/Footer.astro';

const projects = [
  {
    title: '个人博客',
    description: '使用 Astro 构建的个人博客网站,支持 Markdown 写作',
    tags: ['Astro', 'TypeScript', 'CSS'],
    link: '#',
  },
  {
    title: '任务管理应用',
    description: '基于 React 的任务管理应用,支持拖拽排序和分类管理',
    tags: ['React', 'Node.js', 'MongoDB'],
    link: '#',
  },
  {
    title: '电商网站',
    description: '全栈电商项目,包含商品展示、购物车、订单管理功能',
    tags: ['Vue', 'Express', 'PostgreSQL'],
    link: '#',
  },
  {
    title: 'API 文档平台',
    description: '在线 API 文档平台,支持交互式测试和自动生成文档',
    tags: ['Next.js', 'OpenAPI', 'TypeScript'],
    link: '#',
  },
];
---

<Layout title="项目 - 我的主页">
  <Header />
  <main class="main">
    <section class="projects-section">
      <div class="container">
        <h1>我的项目</h1>
        <p class="intro">以下是我参与开发的一些项目,展示了我的技术能力和项目经验。</p>
        
        <div class="projects-grid">
          {projects.map((project) => (
            <article class="project-card">
              <h3 class="project-title">{project.title}</h3>
              <p class="project-description">{project.description}</p>
              <div class="project-tags">
                {project.tags.map((tag) => (
                  <span class="tag">{tag}</span>
                ))}
              </div>
              <a href={project.link} class="project-link">查看详情 →</a>
            </article>
          ))}
        </div>
      </div>
    </section>
  </main>
  <Footer />
</Layout>

<style>
  .main {
    min-height: 100vh;
    padding-top: 80px;
  }

  .projects-section {
    padding: 4rem 2rem;
  }

  .container {
    max-width: 1200px;
    margin: 0 auto;
  }

  h1 {
    font-size: 2.5rem;
    margin-bottom: 1rem;
    color: #1f2937;
  }

  .intro {
    color: #6b7280;
    font-size: 1.1rem;
    margin-bottom: 3rem;
  }

  .projects-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 2rem;
  }

  .project-card {
    background: #fff;
    border: 1px solid #e5e7eb;
    border-radius: 12px;
    padding: 1.5rem;
    transition: transform 0.2s, box-shadow 0.2s;
  }

  .project-card:hover {
    transform: translateY(-4px);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
  }

  .project-title {
    font-size: 1.25rem;
    color: #1f2937;
    margin-bottom: 0.75rem;
  }

  .project-description {
    color: #6b7280;
    line-height: 1.6;
    margin-bottom: 1rem;
  }

  .project-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1rem;
  }

  .tag {
    background: #eff6ff;
    color: #2563eb;
    padding: 0.25rem 0.75rem;
    border-radius: 9999px;
    font-size: 0.875rem;
  }

  .project-link {
    color: #2563eb;
    font-weight: 500;
    display: inline-flex;
    align-items: center;
    transition: color 0.2s;
  }

  .project-link:hover {
    color: #1d4ed8;
  }
</style>

六、运行项目 #

6.1 启动开发服务器 #

bash
npm run dev

访问 http://localhost:4321 查看效果。

6.2 构建生产版本 #

bash
npm run build

6.3 预览构建结果 #

bash
npm run preview

七、项目总结 #

7.1 学到的知识 #

text
┌─────────────────────────────────────────────────────┐
│                   项目知识点总结                     │
├─────────────────────────────────────────────────────┤
│                                                     │
│  ✅ 布局组件的使用                                  │
│     └── 创建可复用的页面布局                        │
│                                                     │
│  ✅ 组件化开发                                      │
│     └── Header、Footer、Hero 等组件                │
│                                                     │
│  ✅ 页面路由                                        │
│     └── 文件即路由,创建多页面                      │
│                                                     │
│  ✅ 样式处理                                        │
│     └── 组件级样式和全局样式                        │
│                                                     │
│  ✅ 数据渲染                                        │
│     └── 使用 map 渲染列表                          │
│                                                     │
└─────────────────────────────────────────────────────┘

7.2 下一步学习 #

下一步,让我们深入学习 组件基础

最后更新:2026-03-28