该项目是一个基于 ReactVite 构建的现代 Web 应用,采用了 TypeScript 进行开发,利用 Tailwind CSS 进行样式设计,并通过 Framer Motion 实现了流畅的交互动画。

本项目只是作为和弦对偶像喜爱的杰作

1. 项目目录结构

项目采用了标准的 Vite + React 结构,核心代码集中在 src 目录下,静态资源管理清晰。

h3R3/
├── public/              # 静态资源目录
│   └── assets/
│       ├── Imager/      # 画廊图片
│       ├── Lyrics/      # LRC 歌词文件
│       ├── Music/       # 音频文件 (.flac)
│       └── ZhuanJiFengMian/ # 专辑封面
├── src/
│   ├── components/      # 核心组件库
│   │   ├── GallerySection.tsx      # 画廊展示模块
│   │   ├── HeroSection.tsx         # 首页视觉模块
│   │   ├── MusicPlayerSection.tsx  # 音乐播放器核心逻辑
│   │   └── ProfileSection.tsx      # 个人简介与专辑列表
│   ├── utils/
│   │   └── assets.ts    # 资源动态加载工具
│   ├── App.tsx          # 主入口与路由控制器
│   ├── main.tsx         # React 渲染入口
│   └── index.css        # 全局样式 (Tailwind 指令)
├── vite.config.ts       # Vite 构建配置
└── package.json         # 依赖管理

2. 核心模块解析

2.1 主控制器:App.tsx

App.tsx 是整个应用的“大脑”,它没有使用传统的 react-router-dom 进行路由跳转,而是实现了一个自定义的全屏滚动(Full-page Scroll)系统

核心逻辑:

  • 使用 useState 管理当前激活的板块索引 currentSection

  • 监听 wheel 滚轮事件,通过计算 deltaY 来判断用户的滚动意图。

  • 使用 CSS transform: translateY 实现平滑的页面切换效果。

// src/App.tsx 核心片段
const App: React.FC = () => {
  const [currentSection, setCurrentSection] = useState(0);
  const [currentAlbum, setCurrentAlbum] = useState<{ path: string; name: string } | null>(null);

  // 滚轮事件处理
  useEffect(() => {
    const handleWheel = (e: WheelEvent) => {
      // 特殊处理 Gallery 内部滚动逻辑
      if (currentSection === 3 && galleryRef.current) {
        // ... 判断是否滚动到底部或顶部,决定是否阻止默认行为
      } else {
        e.preventDefault(); // 阻止默认滚动,接管为全屏切换
      }
      
      // 切换逻辑(防抖处理)
      if (Math.abs(e.deltaY) > 20 && !isScrolling.current) {
        if (e.deltaY > 0 && currentSection < totalSections - 1) {
          setCurrentSection(prev => prev + 1);
        } else if (e.deltaY < 0 && currentSection > 0) {
          setCurrentSection(prev => prev - 1);
        }
      }
    };
    window.addEventListener('wheel', handleWheel, { passive: false });
    return () => window.removeEventListener('wheel', handleWheel);
  }, [currentSection]);

  return (
    <main className="w-full bg-black h-screen overflow-hidden relative">
      <div 
        className="transition-transform duration-700 ease-in-out"
        style={{ transform: `translateY(-${currentSection * 100}vh)` }}
      >
        {/* 各个全屏组件 */}
        <HeroSection />
        <ProfileSection onAlbumClick={handleAlbumClick} />
        <MusicPlayerSection currentAlbum={currentAlbum} />
        <GallerySection />
      </div>
    </main>
  );
};

2.2 音乐播放核心:MusicPlayerSection.tsx

这是逻辑最复杂的组件,负责音频播放、歌词解析和状态同步。

关键功能:LRC 歌词解析
通过正则表达式将 .lrc 文件内容解析为可用的 JS 对象数组。

// src/components/MusicPlayerSection.tsx
const parseLrcLine = (line: string) => {
  // 匹配格式:[00:12.34]歌词内容
  const match = line.match(/\[(\d{2}):(\d{2})\.(\d{2,3})\](.*)/);
  if (!match) return null;
  
  const minutes = parseInt(match[1], 10);
  const seconds = parseInt(match[2], 10);
  const milliseconds = parseInt(match[3], 10);
  
  // 转换为秒数,用于播放器同步
  const time = minutes * 60 + seconds + milliseconds / (match[3].length === 3 ? 1000 : 100);
  return { time, text: match[4].trim() };
};

2.3 资源动态加载:utils/assets.ts

利用 Vite 的 import.meta.glob 特性,实现了自动化的资源导入,无需手动 import 每一个文件。

// src/utils/assets.ts
// 自动扫描目录下的所有封面图片
const albumCoverModules = import.meta.glob('../../public/assets/ZhuanJiFengMian/*.{jpg,jpeg,png,webp}', { eager: true });

export const albumList = Object.entries(albumCoverModules).map(([path, mod]: [string, any]) => {
  const filename = path.split('/').pop() || '';
  // 解码文件名作为专辑名称
  const name = decodeURIComponent(filename.split('.')[0]);
  return {
    name,
    coverPath: mod.default
  };
});

3. 路由与数据流架构

3.1 路由实现

本项目没有使用 URL 路由(如 /about),而是采用了视差滚动单页应用(SPA) 模式。

  • 优点:沉浸感强,转场流畅,像是在浏览一张精心设计的海报。

  • 实现:通过 App.tsx 中的 transform 属性控制视口位置,模拟页面跳转。

3.2 数据流与状态管理

虽然项目中安装了 zustand,但核心逻辑目前主要依赖 React Context 思想的“状态提升(State Lifting)”。

数据流向图:

微信图片_20260221111340_1531_11.png
  1. 交互触发:用户在 ProfileSection 点击专辑。

  2. 状态提升:事件冒泡至 App,更新 currentAlbum 状态,并自动切换 currentSection 至播放器页面。

  3. 单向数据流MusicPlayerSection 接收新的 currentAlbum 属性,触发 useEffect 重新加载音频和歌词。

4. 性能与安全优化

  1. 资源按需加载

    • 歌词文件 (.lrc) 仅在切歌时通过 fetch 动态请求,避免首屏加载过多文本数据。

    • 图片资源通过 Vite 的 glob 导入,构建时自动处理哈希和路径。

  2. 交互性能

    • 使用 requestAnimationFrame 或 React 的 useRef (在滚动监听中) 来避免频繁触发重渲染。

    • 滚动事件通过 isScrolling 标志位实现了防抖(Debounce),防止一次滚轮滑动触发多次翻页。

  3. 动画优化

    • 使用 framer-motionwhileInViewviewport={{ once: true }},确保画廊图片仅在首次进入视口时渲染动画,减少 GPU 消耗。

5. 项目总结

h3R3 个人主页是一个典型的高视觉冲击力 Web 项目。源码结构清晰,充分利用了 Vite 的构建特性简化了资源管理。

亮点总结:

  • 交互细腻:自定义的滚轮阻尼效果和全屏切换逻辑,提供了原生 App 般的体验。

  • 自动化程度高:通过文件名自动生成专辑列表和歌词关联,极大降低了后续维护成本(只需上传文件即可更新内容)。

  • 组件解耦:播放器逻辑与 UI 分离,状态由上层容器管理,易于扩展。

该项目非常适合作为个人作品集艺术家展示页的开发模板。

6. 项目预览

在线地址: http://vincentcassano.cn:1337/

图片预览: