本章概述

在前面的章节中,我们学习了 Tailwind CSS 的各种特性和技术。本章将通过一个完整的实战项目,综合运用所学知识,构建一个现代化的响应式网站。

项目规划

项目概述

我们将构建一个现代化的 SaaS 产品着陆页,包含以下功能:

  • 响应式设计
  • 现代化 UI 组件
  • 动画效果
  • 暗色模式支持
  • 性能优化

技术栈

  • 前端框架: HTML5 + Vanilla JavaScript
  • CSS 框架: Tailwind CSS
  • 构建工具: Vite
  • 图标库: Heroicons
  • 字体: Inter

项目结构

saas-landing/
├── src/
│   ├── index.html
│   ├── styles/
│   │   ├── main.css
│   │   └── components.css
│   ├── js/
│   │   ├── main.js
│   │   └── theme.js
│   └── assets/
│       └── images/
├── tailwind.config.js
├── package.json
└── vite.config.js

环境搭建

1. 初始化项目

# 创建项目目录
mkdir saas-landing
cd saas-landing

# 初始化 npm 项目
npm init -y

# 安装依赖
npm install -D tailwindcss vite autoprefixer postcss
npm install @heroicons/react

# 初始化 Tailwind CSS
npx tailwindcss init -p

2. 配置 Tailwind CSS

// tailwind.config.js
module.exports = {
  content: ['./src/**/*.{html,js}'],
  darkMode: 'class',
  theme: {
    extend: {
      fontFamily: {
        sans: ['Inter', 'sans-serif'],
      },
      colors: {
        primary: {
          50: '#eff6ff',
          500: '#3b82f6',
          600: '#2563eb',
          700: '#1d4ed8',
        },
        gray: {
          900: '#111827',
        },
      },
      animation: {
        'fade-in': 'fadeIn 0.5s ease-in-out',
        'slide-up': 'slideUp 0.5s ease-out',
        'bounce-slow': 'bounce 2s infinite',
      },
      keyframes: {
        fadeIn: {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        slideUp: {
          '0%': { transform: 'translateY(20px)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
      },
    },
  },
  plugins: [],
}

3. 配置 Vite

// vite.config.js
import { defineConfig } from 'vite'

export default defineConfig({
  root: 'src',
  build: {
    outDir: '../dist',
  },
})

页面结构设计

1. HTML 基础结构

<!-- src/index.html -->
<!DOCTYPE html>
<html lang="zh-CN" class="scroll-smooth">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SaaS Landing - 现代化解决方案</title>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
  <link rel="stylesheet" href="./styles/main.css">
</head>
<body class="font-sans antialiased bg-white dark:bg-gray-900 text-gray-900 dark:text-white transition-colors duration-300">
  <!-- 导航栏 -->
  <nav class="fixed top-0 w-full bg-white/80 dark:bg-gray-900/80 backdrop-blur-md border-b border-gray-200 dark:border-gray-700 z-50">
    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
      <div class="flex justify-between items-center h-16">
        <!-- Logo -->
        <div class="flex items-center">
          <div class="flex-shrink-0">
            <h1 class="text-2xl font-bold text-primary-600 dark:text-primary-400">SaaS</h1>
          </div>
        </div>
        
        <!-- 桌面导航 -->
        <div class="hidden md:block">
          <div class="ml-10 flex items-baseline space-x-4">
            <a href="#features" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-sm font-medium transition-colors">功能</a>
            <a href="#pricing" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-sm font-medium transition-colors">定价</a>
            <a href="#about" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-sm font-medium transition-colors">关于</a>
            <a href="#contact" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-sm font-medium transition-colors">联系</a>
          </div>
        </div>
        
        <!-- 右侧按钮 -->
        <div class="flex items-center space-x-4">
          <!-- 主题切换按钮 -->
          <button id="theme-toggle" class="p-2 rounded-lg bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors">
            <svg class="w-5 h-5 hidden dark:block" fill="currentColor" viewBox="0 0 20 20">
              <path fill-rule="evenodd" d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z" clip-rule="evenodd"></path>
            </svg>
            <svg class="w-5 h-5 block dark:hidden" fill="currentColor" viewBox="0 0 20 20">
              <path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
            </svg>
          </button>
          
          <!-- 登录按钮 -->
          <a href="#" class="text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-sm font-medium transition-colors">登录</a>
          
          <!-- 注册按钮 -->
          <a href="#" class="bg-primary-600 hover:bg-primary-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors">免费试用</a>
          
          <!-- 移动端菜单按钮 -->
          <button id="mobile-menu-button" class="md:hidden p-2 rounded-lg text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors">
            <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16"></path>
            </svg>
          </button>
        </div>
      </div>
    </div>
    
    <!-- 移动端菜单 -->
    <div id="mobile-menu" class="md:hidden hidden bg-white dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700">
      <div class="px-2 pt-2 pb-3 space-y-1">
        <a href="#features" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-base font-medium transition-colors">功能</a>
        <a href="#pricing" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-base font-medium transition-colors">定价</a>
        <a href="#about" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-base font-medium transition-colors">关于</a>
        <a href="#contact" class="block text-gray-600 dark:text-gray-300 hover:text-primary-600 dark:hover:text-primary-400 px-3 py-2 rounded-md text-base font-medium transition-colors">联系</a>
      </div>
    </div>
  </nav>

  <!-- 主要内容 -->
  <main class="pt-16">
    <!-- Hero 区域 -->
    <section class="relative bg-gradient-to-br from-primary-50 to-blue-100 dark:from-gray-900 dark:to-gray-800 overflow-hidden">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-24 lg:py-32">
        <div class="text-center">
          <h1 class="text-4xl sm:text-5xl lg:text-6xl font-bold text-gray-900 dark:text-white mb-6 animate-fade-in">
            现代化的
            <span class="text-primary-600 dark:text-primary-400">SaaS 解决方案</span>
          </h1>
          <p class="text-xl text-gray-600 dark:text-gray-300 mb-8 max-w-3xl mx-auto animate-slide-up">
            提供企业级的云服务平台,帮助您的业务快速增长。安全、可靠、易用的解决方案,让您专注于核心业务。
          </p>
          <div class="flex flex-col sm:flex-row gap-4 justify-center animate-slide-up">
            <a href="#" class="bg-primary-600 hover:bg-primary-700 text-white px-8 py-3 rounded-lg text-lg font-medium transition-all duration-300 transform hover:scale-105 shadow-lg hover:shadow-xl">
              免费开始
            </a>
            <a href="#" class="border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 px-8 py-3 rounded-lg text-lg font-medium transition-all duration-300">
              观看演示
            </a>
          </div>
        </div>
      </div>
      
      <!-- 背景装饰 -->
      <div class="absolute top-0 left-0 w-full h-full overflow-hidden pointer-events-none">
        <div class="absolute -top-40 -right-40 w-80 h-80 bg-primary-200 dark:bg-primary-900 rounded-full opacity-20 animate-bounce-slow"></div>
        <div class="absolute -bottom-40 -left-40 w-80 h-80 bg-blue-200 dark:bg-blue-900 rounded-full opacity-20 animate-bounce-slow" style="animation-delay: 1s;"></div>
      </div>
    </section>

    <!-- 功能特性区域 -->
    <section id="features" class="py-24 bg-white dark:bg-gray-900">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="text-center mb-16">
          <h2 class="text-3xl lg:text-4xl font-bold text-gray-900 dark:text-white mb-4">
            强大的功能特性
          </h2>
          <p class="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
            我们提供全面的功能来满足您的业务需求
          </p>
        </div>
        
        <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
          <!-- 功能卡片 1 -->
          <div class="bg-white dark:bg-gray-800 p-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700">
            <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-6">
              <svg class="w-6 h-6 text-primary-600 dark:text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z"></path>
              </svg>
            </div>
            <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">高性能</h3>
            <p class="text-gray-600 dark:text-gray-300">基于云原生架构,提供毫秒级响应速度和99.9%的可用性保证。</p>
          </div>
          
          <!-- 功能卡片 2 -->
          <div class="bg-white dark:bg-gray-800 p-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700">
            <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-6">
              <svg class="w-6 h-6 text-primary-600 dark:text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m5.618-4.016A11.955 11.955 0 0112 2.944a11.955 11.955 0 01-8.618 3.04A12.02 12.02 0 003 9c0 5.591 3.824 10.29 9 11.622 5.176-1.332 9-6.03 9-11.622 0-1.042-.133-2.052-.382-3.016z"></path>
              </svg>
            </div>
            <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">安全可靠</h3>
            <p class="text-gray-600 dark:text-gray-300">企业级安全防护,数据加密传输,符合国际安全标准认证。</p>
          </div>
          
          <!-- 功能卡片 3 -->
          <div class="bg-white dark:bg-gray-800 p-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700">
            <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-6">
              <svg class="w-6 h-6 text-primary-600 dark:text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path>
              </svg>
            </div>
            <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">易于使用</h3>
            <p class="text-gray-600 dark:text-gray-300">直观的用户界面,简单的操作流程,让您快速上手并提高工作效率。</p>
          </div>
          
          <!-- 功能卡片 4 -->
          <div class="bg-white dark:bg-gray-800 p-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700">
            <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-6">
              <svg class="w-6 h-6 text-primary-600 dark:text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 12l3-3 3 3 4-4M8 21l4-4 4 4M3 4h18M4 4h16v12a1 1 0 01-1 1H5a1 1 0 01-1-1V4z"></path>
              </svg>
            </div>
            <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">数据分析</h3>
            <p class="text-gray-600 dark:text-gray-300">实时数据监控和深度分析,帮助您做出更明智的业务决策。</p>
          </div>
          
          <!-- 功能卡片 5 -->
          <div class="bg-white dark:bg-gray-800 p-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700">
            <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-6">
              <svg class="w-6 h-6 text-primary-600 dark:text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0zm6 3a2 2 0 11-4 0 2 2 0 014 0zM7 10a2 2 0 11-4 0 2 2 0 014 0z"></path>
              </svg>
            </div>
            <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">团队协作</h3>
            <p class="text-gray-600 dark:text-gray-300">支持多人协作,权限管理,让团队工作更加高效有序。</p>
          </div>
          
          <!-- 功能卡片 6 -->
          <div class="bg-white dark:bg-gray-800 p-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700">
            <div class="w-12 h-12 bg-primary-100 dark:bg-primary-900 rounded-lg flex items-center justify-center mb-6">
              <svg class="w-6 h-6 text-primary-600 dark:text-primary-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M18.364 5.636l-3.536 3.536m0 5.656l3.536 3.536M9.172 9.172L5.636 5.636m3.536 9.192L5.636 18.364M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-5 0a4 4 0 11-8 0 4 4 0 018 0z"></path>
              </svg>
            </div>
            <h3 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">24/7 支持</h3>
            <p class="text-gray-600 dark:text-gray-300">全天候技术支持,专业团队随时为您解决问题和提供帮助。</p>
          </div>
        </div>
      </div>
    </section>

    <!-- 定价区域 -->
    <section id="pricing" class="py-24 bg-gray-50 dark:bg-gray-800">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
        <div class="text-center mb-16">
          <h2 class="text-3xl lg:text-4xl font-bold text-gray-900 dark:text-white mb-4">
            选择适合您的方案
          </h2>
          <p class="text-xl text-gray-600 dark:text-gray-300 max-w-3xl mx-auto">
            灵活的定价方案,满足不同规模企业的需求
          </p>
        </div>
        
        <div class="grid grid-cols-1 md:grid-cols-3 gap-8">
          <!-- 基础版 -->
          <div class="bg-white dark:bg-gray-900 rounded-xl shadow-lg p-8 border border-gray-200 dark:border-gray-700">
            <div class="text-center mb-8">
              <h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">基础版</h3>
              <p class="text-gray-600 dark:text-gray-300 mb-4">适合小型团队</p>
              <div class="text-4xl font-bold text-gray-900 dark:text-white">
                ¥99
                <span class="text-lg font-normal text-gray-600 dark:text-gray-300">/月</span>
              </div>
            </div>
            <ul class="space-y-4 mb-8">
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">最多 5 个用户</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">10GB 存储空间</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">基础功能</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">邮件支持</span>
              </li>
            </ul>
            <a href="#" class="w-full bg-gray-900 dark:bg-gray-700 text-white py-3 px-6 rounded-lg font-medium hover:bg-gray-800 dark:hover:bg-gray-600 transition-colors text-center block">
              开始使用
            </a>
          </div>
          
          <!-- 专业版 (推荐) -->
          <div class="bg-white dark:bg-gray-900 rounded-xl shadow-xl p-8 border-2 border-primary-500 relative transform scale-105">
            <div class="absolute -top-4 left-1/2 transform -translate-x-1/2">
              <span class="bg-primary-500 text-white px-4 py-1 rounded-full text-sm font-medium">推荐</span>
            </div>
            <div class="text-center mb-8">
              <h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">专业版</h3>
              <p class="text-gray-600 dark:text-gray-300 mb-4">适合中型企业</p>
              <div class="text-4xl font-bold text-gray-900 dark:text-white">
                ¥299
                <span class="text-lg font-normal text-gray-600 dark:text-gray-300">/月</span>
              </div>
            </div>
            <ul class="space-y-4 mb-8">
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">最多 25 个用户</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">100GB 存储空间</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">高级功能</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">优先支持</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">API 访问</span>
              </li>
            </ul>
            <a href="#" class="w-full bg-primary-600 text-white py-3 px-6 rounded-lg font-medium hover:bg-primary-700 transition-colors text-center block">
              开始使用
            </a>
          </div>
          
          <!-- 企业版 -->
          <div class="bg-white dark:bg-gray-900 rounded-xl shadow-lg p-8 border border-gray-200 dark:border-gray-700">
            <div class="text-center mb-8">
              <h3 class="text-2xl font-bold text-gray-900 dark:text-white mb-2">企业版</h3>
              <p class="text-gray-600 dark:text-gray-300 mb-4">适合大型企业</p>
              <div class="text-4xl font-bold text-gray-900 dark:text-white">
                ¥999
                <span class="text-lg font-normal text-gray-600 dark:text-gray-300">/月</span>
              </div>
            </div>
            <ul class="space-y-4 mb-8">
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">无限用户</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">1TB 存储空间</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">全部功能</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">专属客服</span>
              </li>
              <li class="flex items-center">
                <svg class="w-5 h-5 text-green-500 mr-3" fill="currentColor" viewBox="0 0 20 20">
                  <path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path>
                </svg>
                <span class="text-gray-600 dark:text-gray-300">定制开发</span>
              </li>
            </ul>
            <a href="#" class="w-full bg-gray-900 dark:bg-gray-700 text-white py-3 px-6 rounded-lg font-medium hover:bg-gray-800 dark:hover:bg-gray-600 transition-colors text-center block">
              联系销售
            </a>
          </div>
        </div>
      </div>
    </section>

    <!-- CTA 区域 -->
    <section class="py-24 bg-primary-600 dark:bg-primary-700">
      <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center">
        <h2 class="text-3xl lg:text-4xl font-bold text-white mb-4">
          准备开始了吗?
        </h2>
        <p class="text-xl text-primary-100 mb-8 max-w-3xl mx-auto">
          立即注册,享受 14 天免费试用,无需信用卡
        </p>
        <div class="flex flex-col sm:flex-row gap-4 justify-center">
          <a href="#" class="bg-white text-primary-600 px-8 py-3 rounded-lg text-lg font-medium hover:bg-gray-100 transition-colors">
            免费试用
          </a>
          <a href="#" class="border border-white text-white hover:bg-white hover:text-primary-600 px-8 py-3 rounded-lg text-lg font-medium transition-colors">
            联系我们
          </a>
        </div>
      </div>
    </section>
  </main>

  <!-- 页脚 -->
  <footer class="bg-gray-900 dark:bg-gray-950 text-white">
    <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
      <div class="grid grid-cols-1 md:grid-cols-4 gap-8">
        <div class="col-span-1 md:col-span-2">
          <h3 class="text-2xl font-bold text-primary-400 mb-4">SaaS</h3>
          <p class="text-gray-300 mb-4 max-w-md">
            提供现代化的云服务解决方案,帮助企业实现数字化转型,提高业务效率。
          </p>
          <div class="flex space-x-4">
            <a href="#" class="text-gray-400 hover:text-white transition-colors">
              <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
                <path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z"/>
              </svg>
            </a>
            <a href="#" class="text-gray-400 hover:text-white transition-colors">
              <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
                <path d="M22.46 6c-.77.35-1.6.58-2.46.69.88-.53 1.56-1.37 1.88-2.38-.83.5-1.75.85-2.72 1.05C18.37 4.5 17.26 4 16 4c-2.35 0-4.27 1.92-4.27 4.29 0 .34.04.67.11.98C8.28 9.09 5.11 7.38 3 4.79c-.37.63-.58 1.37-.58 2.15 0 1.49.75 2.81 1.91 3.56-.71 0-1.37-.2-1.95-.5v.03c0 2.08 1.48 3.82 3.44 4.21a4.22 4.22 0 0 1-1.93.07 4.28 4.28 0 0 0 4 2.98 8.521 8.521 0 0 1-5.33 1.84c-.34 0-.68-.02-1.02-.06C3.44 20.29 5.7 21 8.12 21 16 21 20.33 14.46 20.33 8.79c0-.19 0-.37-.01-.56.84-.6 1.56-1.36 2.14-2.23z"/>
              </svg>
            </a>
            <a href="#" class="text-gray-400 hover:text-white transition-colors">
              <svg class="w-6 h-6" fill="currentColor" viewBox="0 0 24 24">
                <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433c-1.144 0-2.063-.926-2.063-2.065 0-1.138.92-2.063 2.063-2.063 1.14 0 2.064.925 2.064 2.063 0 1.139-.925 2.065-2.064 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
              </svg>
            </a>
          </div>
        </div>
        
        <div>
          <h4 class="text-lg font-semibold mb-4">产品</h4>
          <ul class="space-y-2">
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">功能特性</a></li>
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">定价方案</a></li>
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">API 文档</a></li>
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">集成</a></li>
          </ul>
        </div>
        
        <div>
          <h4 class="text-lg font-semibold mb-4">支持</h4>
          <ul class="space-y-2">
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">帮助中心</a></li>
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">联系我们</a></li>
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">状态页面</a></li>
            <li><a href="#" class="text-gray-300 hover:text-white transition-colors">社区</a></li>
          </ul>
        </div>
      </div>
      
      <div class="border-t border-gray-800 mt-12 pt-8 flex flex-col md:flex-row justify-between items-center">
        <p class="text-gray-400 text-sm">
          © 2024 SaaS. 保留所有权利。
        </p>
        <div class="flex space-x-6 mt-4 md:mt-0">
          <a href="#" class="text-gray-400 hover:text-white text-sm transition-colors">隐私政策</a>
          <a href="#" class="text-gray-400 hover:text-white text-sm transition-colors">服务条款</a>
          <a href="#" class="text-gray-400 hover:text-white text-sm transition-colors">Cookie 政策</a>
        </div>
      </div>
    </div>
  </footer>

  <script src="./js/main.js"></script>
</body>
</html>

JavaScript 功能实现

1. 主题切换功能

// src/js/theme.js
class ThemeManager {
  constructor() {
    this.theme = localStorage.getItem('theme') || 'light'
    this.init()
  }

  init() {
    this.applyTheme()
    this.bindEvents()
  }

  applyTheme() {
    if (this.theme === 'dark') {
      document.documentElement.classList.add('dark')
    } else {
      document.documentElement.classList.remove('dark')
    }
  }

  toggleTheme() {
    this.theme = this.theme === 'light' ? 'dark' : 'light'
    localStorage.setItem('theme', this.theme)
    this.applyTheme()
  }

  bindEvents() {
    const themeToggle = document.getElementById('theme-toggle')
    if (themeToggle) {
      themeToggle.addEventListener('click', () => this.toggleTheme())
    }
  }
}

// 导出主题管理器
window.ThemeManager = ThemeManager

2. 移动端菜单

// src/js/mobile-menu.js
class MobileMenu {
  constructor() {
    this.isOpen = false
    this.init()
  }

  init() {
    this.bindEvents()
  }

  toggle() {
    this.isOpen = !this.isOpen
    const menu = document.getElementById('mobile-menu')
    const button = document.getElementById('mobile-menu-button')
    
    if (this.isOpen) {
      menu.classList.remove('hidden')
      button.setAttribute('aria-expanded', 'true')
    } else {
      menu.classList.add('hidden')
      button.setAttribute('aria-expanded', 'false')
    }
  }

  close() {
    this.isOpen = false
    const menu = document.getElementById('mobile-menu')
    const button = document.getElementById('mobile-menu-button')
    
    menu.classList.add('hidden')
    button.setAttribute('aria-expanded', 'false')
  }

  bindEvents() {
    const button = document.getElementById('mobile-menu-button')
    if (button) {
      button.addEventListener('click', () => this.toggle())
    }

    // 点击菜单项时关闭菜单
    const menuItems = document.querySelectorAll('#mobile-menu a')
    menuItems.forEach(item => {
      item.addEventListener('click', () => this.close())
    })

    // 点击外部区域关闭菜单
    document.addEventListener('click', (e) => {
      const menu = document.getElementById('mobile-menu')
      const button = document.getElementById('mobile-menu-button')
      
      if (this.isOpen && !menu.contains(e.target) && !button.contains(e.target)) {
        this.close()
      }
    })
  }
}

// 导出移动端菜单
window.MobileMenu = MobileMenu

3. 滚动动画

// src/js/scroll-animations.js
class ScrollAnimations {
  constructor() {
    this.init()
  }

  init() {
    this.setupIntersectionObserver()
    this.setupSmoothScroll()
  }

  setupIntersectionObserver() {
    const options = {
      threshold: 0.1,
      rootMargin: '0px 0px -50px 0px'
    }

    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          entry.target.classList.add('animate-fade-in')
        }
      })
    }, options)

    // 观察需要动画的元素
    const animatedElements = document.querySelectorAll('.animate-on-scroll')
    animatedElements.forEach(el => observer.observe(el))
  }

  setupSmoothScroll() {
    // 平滑滚动到锚点
    const links = document.querySelectorAll('a[href^="#"]')
    links.forEach(link => {
      link.addEventListener('click', (e) => {
        e.preventDefault()
        const targetId = link.getAttribute('href').substring(1)
        const targetElement = document.getElementById(targetId)
        
        if (targetElement) {
          targetElement.scrollIntoView({
            behavior: 'smooth',
            block: 'start'
          })
        }
      })
    })
  }
}

// 导出滚动动画
window.ScrollAnimations = ScrollAnimations

4. 主入口文件

// src/js/main.js
// 等待 DOM 加载完成
document.addEventListener('DOMContentLoaded', () => {
  // 初始化主题管理器
  const themeManager = new ThemeManager()
  
  // 初始化移动端菜单
  const mobileMenu = new MobileMenu()
  
  // 初始化滚动动画
  const scrollAnimations = new ScrollAnimations()
  
  // 导航栏滚动效果
  let lastScrollY = window.scrollY
  const navbar = document.querySelector('nav')
  
  window.addEventListener('scroll', () => {
    const currentScrollY = window.scrollY
    
    if (currentScrollY > 100) {
      navbar.classList.add('shadow-lg')
    } else {
      navbar.classList.remove('shadow-lg')
    }
    
    lastScrollY = currentScrollY
  })
  
  // 添加加载动画
  document.body.classList.add('animate-fade-in')
  
  console.log('SaaS Landing Page 已加载完成')
})

CSS 样式文件

1. 主样式文件

/* src/styles/main.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* 自定义基础样式 */
@layer base {
  html {
    scroll-behavior: smooth;
  }
  
  body {
    @apply font-sans antialiased;
  }
}

/* 自定义组件样式 */
@layer components {
  .btn-primary {
    @apply bg-primary-600 hover:bg-primary-700 text-white px-6 py-3 rounded-lg font-medium transition-all duration-300 transform hover:scale-105 shadow-lg hover:shadow-xl;
  }
  
  .btn-secondary {
    @apply border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 px-6 py-3 rounded-lg font-medium transition-all duration-300;
  }
  
  .card {
    @apply bg-white dark:bg-gray-800 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700;
  }
  
  .section-padding {
    @apply py-24;
  }
  
  .container-padding {
    @apply max-w-7xl mx-auto px-4 sm:px-6 lg:px-8;
  }
}

/* 自定义工具类 */
@layer utilities {
  .text-gradient {
    @apply bg-gradient-to-r from-primary-600 to-blue-600 bg-clip-text text-transparent;
  }
  
  .bg-gradient-primary {
    @apply bg-gradient-to-br from-primary-50 to-blue-100 dark:from-gray-900 dark:to-gray-800;
  }
  
  .backdrop-blur-nav {
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
  }
}

/* 动画样式 */
@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(20px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translateY(30px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes bounceIn {
  0% {
    opacity: 0;
    transform: scale(0.3);
  }
  50% {
    opacity: 1;
    transform: scale(1.05);
  }
  70% {
    transform: scale(0.9);
  }
  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* 响应式隐藏类 */
.animate-on-scroll {
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s ease-out;
}

.animate-on-scroll.animate-fade-in {
  opacity: 1;
  transform: translateY(0);
}

/* 加载状态 */
.loading {
  @apply animate-pulse;
}

/* 自定义滚动条 */
::-webkit-scrollbar {
  width: 8px;
}

::-webkit-scrollbar-track {
  @apply bg-gray-100 dark:bg-gray-800;
}

::-webkit-scrollbar-thumb {
  @apply bg-gray-300 dark:bg-gray-600 rounded-full;
}

::-webkit-scrollbar-thumb:hover {
  @apply bg-gray-400 dark:bg-gray-500;
}

2. 组件样式文件

/* src/styles/components.css */
/* 导航栏组件 */
.navbar {
  @apply fixed top-0 w-full bg-white/80 dark:bg-gray-900/80 backdrop-blur-md border-b border-gray-200 dark:border-gray-700 z-50 transition-all duration-300;
}

.navbar.scrolled {
  @apply shadow-lg bg-white/95 dark:bg-gray-900/95;
}

/* 卡片组件 */
.feature-card {
  @apply bg-white dark:bg-gray-800 p-8 rounded-xl shadow-lg hover:shadow-xl transition-all duration-300 transform hover:-translate-y-2 border border-gray-100 dark:border-gray-700;
}

.feature-card:hover {
  @apply scale-105;
}

/* 定价卡片 */
.pricing-card {
  @apply bg-white dark:bg-gray-900 rounded-xl shadow-lg p-8 border border-gray-200 dark:border-gray-700 transition-all duration-300;
}

.pricing-card.featured {
  @apply border-2 border-primary-500 transform scale-105 shadow-xl;
}

.pricing-card.featured::before {
  content: '推荐';
  @apply absolute -top-4 left-1/2 transform -translate-x-1/2 bg-primary-500 text-white px-4 py-1 rounded-full text-sm font-medium;
}

/* 按钮组件 */
.btn {
  @apply px-6 py-3 rounded-lg font-medium transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-offset-2;
}

.btn-primary {
  @apply bg-primary-600 hover:bg-primary-700 text-white focus:ring-primary-500 transform hover:scale-105 shadow-lg hover:shadow-xl;
}

.btn-secondary {
  @apply border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 focus:ring-gray-500;
}

.btn-outline {
  @apply border border-current text-current hover:bg-current hover:text-white;
}

/* 表单组件 */
.form-input {
  @apply w-full px-4 py-3 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-primary-500 focus:border-transparent bg-white dark:bg-gray-800 text-gray-900 dark:text-white transition-colors;
}

.form-label {
  @apply block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2;
}

/* 图标组件 */
.icon {
  @apply w-6 h-6;
}

.icon-sm {
  @apply w-4 h-4;
}

.icon-lg {
  @apply w-8 h-8;
}

/* 徽章组件 */
.badge {
  @apply inline-flex items-center px-3 py-1 rounded-full text-sm font-medium;
}

.badge-primary {
  @apply bg-primary-100 text-primary-800 dark:bg-primary-900 dark:text-primary-200;
}

.badge-success {
  @apply bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200;
}

.badge-warning {
  @apply bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-200;
}

.badge-error {
  @apply bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200;
}

构建配置

1. Package.json

{
  "name": "saas-landing",
  "version": "1.0.0",
  "description": "现代化 SaaS 产品着陆页",
  "main": "index.js",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview",
    "build-css": "tailwindcss -i ./src/styles/main.css -o ./dist/styles/main.css --watch"
  },
  "keywords": ["tailwind", "css", "saas", "landing", "responsive"],
  "author": "Your Name",
  "license": "MIT",
  "devDependencies": {
    "autoprefixer": "^10.4.16",
    "postcss": "^8.4.32",
    "tailwindcss": "^3.3.6",
    "vite": "^5.0.8"
  },
  "dependencies": {
    "@heroicons/react": "^2.0.18"
  }
}

2. PostCSS 配置

// postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

性能优化

1. 图片优化

// src/js/image-optimization.js
class ImageOptimization {
  constructor() {
    this.init()
  }

  init() {
    this.setupLazyLoading()
    this.setupWebPSupport()
  }

  setupLazyLoading() {
    const images = document.querySelectorAll('img[data-src]')
    
    const imageObserver = new IntersectionObserver((entries, observer) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          const img = entry.target
          img.src = img.dataset.src
          img.classList.remove('loading')
          observer.unobserve(img)
        }
      })
    })

    images.forEach(img => imageObserver.observe(img))
  }

  setupWebPSupport() {
    const supportsWebP = () => {
      const canvas = document.createElement('canvas')
      return canvas.toDataURL('image/webp').indexOf('webp') > -1
    }

    if (supportsWebP()) {
      document.documentElement.classList.add('webp')
    }
  }
}

// 导出图片优化
window.ImageOptimization = ImageOptimization

2. 代码分割

// src/js/code-splitting.js
class CodeSplitting {
  constructor() {
    this.loadedModules = new Set()
  }

  async loadModule(moduleName) {
    if (this.loadedModules.has(moduleName)) {
      return
    }

    try {
      switch (moduleName) {
        case 'analytics':
          await import('./analytics.js')
          break
        case 'chat':
          await import('./chat.js')
          break
        default:
          console.warn(`Unknown module: ${moduleName}`)
      }
      
      this.loadedModules.add(moduleName)
    } catch (error) {
      console.error(`Failed to load module ${moduleName}:`, error)
    }
  }

  loadOnDemand() {
    // 滚动到页面底部时加载聊天模块
    const observer = new IntersectionObserver((entries) => {
      entries.forEach(entry => {
        if (entry.isIntersecting) {
          this.loadModule('chat')
          observer.unobserve(entry.target)
        }
      })
    })

    const footer = document.querySelector('footer')
    if (footer) {
      observer.observe(footer)
    }
  }
}

// 导出代码分割
window.CodeSplitting = CodeSplitting

部署配置

1. 构建脚本

#!/bin/bash
# build.sh

echo "开始构建 SaaS Landing Page..."

# 清理旧的构建文件
rm -rf dist

# 构建项目
npm run build

# 复制静态资源
cp -r src/assets dist/

# 生成 sitemap
echo "生成 sitemap..."
cat > dist/sitemap.xml << EOF
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://your-domain.com/</loc>
    <lastmod>$(date +%Y-%m-%d)</lastmod>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
  </url>
</urlset>
EOF

# 生成 robots.txt
cat > dist/robots.txt << EOF
User-agent: *
Allow: /

Sitemap: https://your-domain.com/sitemap.xml
EOF

echo "构建完成!"

2. Nginx 配置

# nginx.conf
server {
    listen 80;
    server_name your-domain.com;
    root /var/www/saas-landing/dist;
    index index.html;

    # 启用 gzip 压缩
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;

    # 静态资源缓存
    location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
    }

    # HTML 文件不缓存
    location ~* \.html$ {
        expires -1;
        add_header Cache-Control "no-cache, no-store, must-revalidate";
    }

    # 单页应用路由
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 安全头
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-XSS-Protection "1; mode=block" always;
}

测试与调试

1. 性能测试

// src/js/performance.js
class PerformanceMonitor {
  constructor() {
    this.metrics = {}
    this.init()
  }

  init() {
    this.measurePageLoad()
    this.measureInteractions()
  }

  measurePageLoad() {
    window.addEventListener('load', () => {
      const navigation = performance.getEntriesByType('navigation')[0]
      
      this.metrics.pageLoad = {
        domContentLoaded: navigation.domContentLoadedEventEnd - navigation.domContentLoadedEventStart,
        loadComplete: navigation.loadEventEnd - navigation.loadEventStart,
        totalTime: navigation.loadEventEnd - navigation.fetchStart
      }
      
      console.log('页面加载性能:', this.metrics.pageLoad)
    })
  }

  measureInteractions() {
    // 测量首次输入延迟 (FID)
    new PerformanceObserver((entryList) => {
      for (const entry of entryList.getEntries()) {
        this.metrics.fid = entry.processingStart - entry.startTime
        console.log('首次输入延迟:', this.metrics.fid)
      }
    }).observe({ type: 'first-input', buffered: true })

    // 测量累积布局偏移 (CLS)
    let clsValue = 0
    new PerformanceObserver((entryList) => {
      for (const entry of entryList.getEntries()) {
        if (!entry.hadRecentInput) {
          clsValue += entry.value
        }
      }
      this.metrics.cls = clsValue
      console.log('累积布局偏移:', this.metrics.cls)
    }).observe({ type: 'layout-shift', buffered: true })
  }

  getMetrics() {
    return this.metrics
  }
}

// 导出性能监控
window.PerformanceMonitor = PerformanceMonitor

2. 错误处理

// src/js/error-handling.js
class ErrorHandler {
  constructor() {
    this.init()
  }

  init() {
    this.setupGlobalErrorHandler()
    this.setupUnhandledRejectionHandler()
  }

  setupGlobalErrorHandler() {
    window.addEventListener('error', (event) => {
      this.logError({
        type: 'JavaScript Error',
        message: event.message,
        filename: event.filename,
        lineno: event.lineno,
        colno: event.colno,
        stack: event.error?.stack
      })
    })
  }

  setupUnhandledRejectionHandler() {
    window.addEventListener('unhandledrejection', (event) => {
      this.logError({
        type: 'Unhandled Promise Rejection',
        message: event.reason?.message || event.reason,
        stack: event.reason?.stack
      })
    })
  }

  logError(error) {
    console.error('错误详情:', error)
    
    // 在生产环境中,可以发送错误到监控服务
    if (process.env.NODE_ENV === 'production') {
      this.sendErrorToService(error)
    }
  }

  sendErrorToService(error) {
    // 发送错误到监控服务(如 Sentry、LogRocket 等)
    fetch('/api/errors', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        ...error,
        timestamp: new Date().toISOString(),
        userAgent: navigator.userAgent,
        url: window.location.href
      })
    }).catch(err => {
      console.error('发送错误日志失败:', err)
    })
  }
}

// 导出错误处理
window.ErrorHandler = ErrorHandler

项目总结

实现的功能

  1. 响应式设计: 适配各种设备尺寸
  2. 暗色模式: 支持主题切换
  3. 现代化 UI: 使用 Tailwind CSS 构建
  4. 性能优化: 图片懒加载、代码分割
  5. 动画效果: 平滑的交互动画
  6. 移动端友好: 移动端菜单和触摸优化
  7. SEO 优化: 语义化 HTML 和 meta 标签
  8. 可访问性: 键盘导航和屏幕阅读器支持

技术亮点

  1. 模块化架构: JavaScript 代码按功能模块组织
  2. 组件化 CSS: 使用 @apply 指令创建可复用组件
  3. 性能监控: 内置性能指标收集
  4. 错误处理: 完善的错误捕获和上报机制
  5. 构建优化: 使用 Vite 进行快速构建

最佳实践

  1. 代码组织: 清晰的文件结构和命名规范
  2. 性能优化: 图片优化、代码分割、缓存策略
  3. 用户体验: 加载状态、错误提示、平滑动画
  4. 可维护性: 模块化代码、详细注释、类型检查
  5. 部署配置: 自动化构建、服务器配置、监控设置

本章总结

通过本章的实战项目,我们:

  1. 综合运用了 Tailwind CSS 的各种特性
  2. 构建了一个完整的现代化网站
  3. 实现了响应式设计和暗色模式
  4. 优化了性能和用户体验
  5. 建立了完整的开发和部署流程

这个项目展示了如何使用 Tailwind CSS 构建生产级别的网站,包含了从设计到部署的完整流程。

练习题

  1. 功能扩展: 为网站添加多语言支持
  2. 性能优化: 实现 Service Worker 缓存策略
  3. 交互增强: 添加更多动画效果和微交互
  4. 数据集成: 连接后端 API 实现动态内容
  5. 测试完善: 编写单元测试和端到端测试

下一步

在下一章中,我们将学习 总结与最佳实践,回顾整个 Tailwind CSS 学习过程,总结最佳实践和常见问题解决方案。