资源推荐
React Three Fiber 作品集项目推荐

今天介绍一个非常值得参考的开源项目,它结合了 React、Tailwind CSS、Framer Motion 和 React Three Fiber。

采用 3D 场景作为首页背景,页面结构清晰,整体风格简洁现代,适合用于展示前端开发者的个人信息和项目经历。

一、项目概览

  • 🔧 主要技术栈
    • 前端框架:React
    • 样式系统:Tailwind CSS
    • 构建工具:Vite
    • 动画交互:Framer Motion、Typewriter、Lottie
    • 图标系统:React Icons
    • 3D 渲染:React Three Fiber(R3F) + Drei

GitHub 地址: https://github.com/Khizar2004/Portfolio (opens in a new tab)

二、功能介绍

场景展示

1

颜色切换

2

物体点击展示

3

三、快速上手指南

本项目基于 Vite 开发,启动非常快捷:

git clone https://github.com/Khizar2004/Portfolio.git
cd Portfolio
npm install
npm run start

然后打开浏览器访问 http://localhost:3000 即可查看本地运行效果。

核心代码解释

核心代码梳理

1. 项目入口与应用根组件

src/App.tsx

这是应用的起点。它负责设置全局样式、主题上下文 (ThemeProvider)、声音上下文 (SoundProvider),并渲染主场景。

  • ThemeProvider: 管理应用的深色/浅色主题。
  • SoundProvider: 全局控制声音的播放与开关。
  • LoadingScreen: 在资源加载时显示的加载界面。
  • MainScene: 渲染所有 3D 元素和交互式 UI 的核心场景组件。
  • HtmlContextWrapper: 一个包裹器,可能用于管理在 3D 场景中渲染的 HTML 内容。
// src/App.tsx
import React, { Suspense } from 'react';
// ... 其他导入 ...
import { ThemeProvider }s from './context/ThemeContext';
import { SoundProvider } from './context/SoundContext';
import MainScene from './scenes/MainScene';
import { LoadingScreen } from './components/ui/LoadingScreen';
import HtmlContextWrapper from './components/ui/HtmlContextWrapper';
 
function App() {
  return (
    <ThemeProvider>
      <SoundProvider>
        <Suspense fallback={<LoadingScreen />}>
          <HtmlContextWrapper>
            <MainScene />
          </HtmlContextWrapper>
        </Suspense>
      </SoundProvider>
    </ThemeProvider>
  );
}
 
export default App;

2. 3D 场景主入口

src/scenes/MainScene.tsx

这是项目的核心,负责搭建 3D 世界。它使用 react-three-fiber<Canvas> 组件作为 3D 渲染的根。

  • <Canvas>: 创建一个 WebGL 渲染上下文。
  • WorkspaceEnvironment: 设置场景的环境光、相机动画和整体氛围。
  • InteractiveObjects: 负责渲染场景中所有可交互的 3D 对象。
  • UI 组件: 如 AboutMe, Contact, Resume 等,它们是标准的 React 组件,通过 react-three-dreiHtml 组件被渲染到 3D 场景的特定位置。
// src/scenes/MainScene.tsx
import { Canvas } from "@react-three/fiber";
// ... 其他导入 ...
import WorkspaceEnvironment from "../components/3d/WorkspaceEnvironment";
import InteractiveObjects from "../components/3d/InteractiveObjects";
import AboutMe from "../components/ui/AboutMe";
// ... 其他 UI 组件 ...
 
const MainScene = () => {
  // ...
  return (
    <>
      <Canvas>
        <WorkspaceEnvironment />
        <InteractiveObjects />
      </Canvas>
      {/* UI Components */}
      <AboutMe />
      <Contact />
      {/* ... */}
    </>
  );
};

3. 交互式 3D 对象

src/components/3d/InteractiveObjects.tsx

这个组件是动态加载和管理场景中所有 3D 模型的关键。它读取一个配置文件(或直接定义一个列表),然后循环渲染每一个 InteractiveObject

  • 它定义了每个 3D 模型的位置、旋转、缩放等属性。
  • 它为每个模型关联了点击后需要显示的 UI 组件 (focusContent)。
// src/components/3d/InteractiveObjects.tsx
import React from "react";
import InteractiveObject from "./InteractiveObject";
// ... 导入所有 3D 模型组件 ...
 
const InteractiveObjects = () => {
  const objects = [
    {
      model: <PC />,
      position: [0, 0, 0],
      focusContent: "pc", // 关联 UI
    },
    {
      model: <Chair />,
      position: [1, -1.5, 1],
      focusContent: "chair",
    },
    // ... 其他所有对象
  ];
 
  return (
    <>
      {objects.map((obj, index) => (
        <InteractiveObject key={index} {...obj} />
      ))}
    </>
  );
};
 
export default InteractiveObjects;

4. 单个可交互对象

src/components/3d/InteractiveObject.tsx

这是实现 3D 对象交互功能的核心。它包裹了每个 3D 模型,并添加了事件监听器。

  • useRef: 用于获取对 3D 对象的直接引用。
  • useFrame: react-three-fiber 的一个 hook,用于在每一帧执行代码,这里用它来实现鼠标悬浮时的动画效果(例如,轻微浮动)。
  • 事件处理:
    • onPointerOver: 鼠标悬浮时,改变鼠标指针样式并触发动画。
    • onPointerOut: 鼠标移出时,恢复默认状态。
    • onClick: 点击时,播放音效并触发全局状态更新,通知应用显示对应的 UI 界面(例如,点击电脑显示项目介绍)。
// src/components/3d/InteractiveObject.tsx
import React, { useRef, useState } from "react";
import { useFrame } from "@react-three/fiber";
// ...
 
const InteractiveObject = ({ model, position, focusContent }) => {
  const ref = useRef();
  const [hovered, setHovered] = useState(false);
 
  // 每一帧都调用,实现悬浮动画
  useFrame(() => {
    if (hovered && ref.current) {
      // ... 实现上下浮动的动画逻辑 ...
    }
  });
 
  const handleClick = () => {
    // ... 播放点击音效 ...
    // ... 更新全局状态,显示关联的 UI ...
  };
 
  return (
    <group
      ref={ref}
      position={position}
      onPointerOver={() => setHovered(true)}
      onPointerOut={() => setHovered(false)}
      onClick={handleClick}
    >
      {model}
    </group>
  );
};

5. 全局状态管理

src/context/ThemeContext.tsx

为了在整个应用中共享状态(如主题、当前聚焦的物体等),项目使用了 React Context。ThemeContext 是一个很好的例子。

  • createContext: 创建一个上下文对象。
  • ThemeProvider: 一个包裹组件,通过 value 属性将其内部的状态和方法传递给所有子组件。
  • useTheme: 一个自定义 hook,让任何子组件都能轻松地访问和修改主题状态。
// src/context/ThemeContext.tsx
import React, { createContext, useContext, useState } from "react";
 
const ThemeContext = createContext(null);
 
export const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState("dark");
  // ... 其他状态,例如当前聚焦的对象
 
  const toggleTheme = () => {
    setTheme(theme === "dark" ? "light" : "dark");
  };
 
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};
 
export const useTheme = () => useContext(ThemeContext);

总结

  • App.tsx 作为顶层容器,负责组装上下文和核心组件。
  • MainScene.tsx 负责搭建 3D 画布和集成 UI。
  • InteractiveObjects.tsx 负责布局场景中的所有 3D 模型。
  • InteractiveObject.tsx 负责实现单个模型的交互逻辑和动画。
  • Context API (SoundContext, ThemeContext) 用于解耦组件间的通信,管理全局状态。