今天介绍一个非常值得参考的开源项目,它结合了 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-drei的Html组件被渲染到 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) 用于解耦组件间的通信,管理全局状态。