3D 作品集
界面
现在我们已经完成了 3D 场景的主要部分,可以开始制作 HTML 界面。
让我们创建一个与 3D 场景相同 4 个部分的 Interface.jsx
组件:
export const Interface = () => { return ( <div className="interface"> <div className="sections"> {/* HOME */} <section className="section section--bottom">HOME</section> {/* SKILLS */} <section className="section section--right">SKILLS</section> {/* PROJECTS */} <section className="section section--left">PROJECTS</section> {/* CONTACT */} <section className="section section--left">CONTACT</section> </div> </div> ); };
我们将使用 section--bottom
、section--right
和 section--left
类来定位部分内的内容。
目前我们只是添加了部分名称,稍后我们会添加内容。
将 Interface
组件添加到 App
组件中:
import { Scroll, ScrollControls } from "@react-three/drei"; import { Canvas } from "@react-three/fiber"; import { MotionConfig } from "framer-motion"; import { Experience } from "./components/Experience"; import { config } from "./config"; import { Interface } from "./components/Interface"; function App() { return ( <> <Canvas camera={{ position: [0, 0.5, 5], fov: 42 }}> <color attach="background" args={["#f5f3ee"]} /> <fog attach="fog" args={["#f5f3ee", 10, 50]} /> <ScrollControls pages={config.sections.length} damping={0.1} maxSpeed={0.2} > <group position-y={-1}> <MotionConfig transition={{ duration: 0.6, }} > <Experience /> </MotionConfig> </group> <Scroll html> <Interface /> </Scroll> </ScrollControls> </Canvas> </> ); } export default App;
为了样式化我们的 HTML 界面,我们将使用 vanilla CSS 以确保尽可能的通用。如果你愿意,可以使用你喜欢的 CSS 框架(我在大多数项目中使用了 TailwindCSS)。
让我们在 index.css
文件中添加默认样式:
@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@400;700&display=swap"); :root { --primary-color: #4668ee; --text-color: #1a202c; --text-light-color: #555; } #root { width: 100vw; height: 100vh; } body { margin: 0; font-family: "Roboto Slab", serif; } /* ... */ .interface { width: 100vw; display: flex; flex-direction: column; align-items: center; } .sections { max-width: 1200px; width: 100%; } .section { height: 100vh; display: flex; justify-content: center; align-items: center; } .section--top { align-items: flex-start; } .section--bottom { align-items: flex-end; } .section--right { justify-content: flex-end; } .section--left { justify-content: flex-start; }
我们从 Google Fonts 导入了 Roboto Slab 字体,并定义了一些 颜色变量。
部分的容器是居中的,并具有 1200px
的 max-width
以确保在大屏幕上有良好的可读性。
部分的 height
为 100vh
(全高) 并且默认居中显示。我们将使用 section--top
、section--bottom
、section--right
和 section--left
类来定位部分内的内容。
我们的界面准备好了,现在让我们添加内容吧!
首页滚动指示器
在首页部分,我们将添加一个滚动指示器,提示用户可以滚动查看其他部分。
首先,让我们创建一个 state 来判断用户是否已经滚动:
import { useScroll } from "@react-three/drei"; import { useFrame } from "@react-three/fiber"; import { useState } from "react"; export const Interface = () => { const scrollData = useScroll(); const [hasScrolled, setHasScrolled] = useState(false); useFrame(() => { setHasScrolled(scrollData.offset > 0); }); // ... };
然后在首页部分,我们可以添加一个带有 variants
对象的 motion.div
来创建一个动画滚动指示器:
// ... import { motion } from "framer-motion"; export const Interface = () => { // ... return ( <div className="interface"> <div className="sections"> {/* HOME */} <section className="section section--bottom"> <motion.div className="scroll-down" initial={{ opacity: 0, }} animate={{ opacity: hasScrolled ? 0 : 1, }} > <motion.div className="scroll-down__wheel" initial={{ translateY: 0, }} animate={{ translateY: 4, }} transition={{ duration: 0.4, repeatDelay: 0.5, repeatType: "reverse", repeat: Infinity, }} ></motion.div> </motion.div> </section> {/* ... */} </div> </div> ); };
我们使用 framer motion 来动画处理透明度和滚轮位置。为了让滚轮上下移动,我们使用了 repeat
和 repeatType
属性。
React Three Fiber: The Ultimate Guide to 3D Web Development
✨ You have reached the end of the preview ✨
Go to the next level with Three.js and React Three Fiber!
Get full access to this lesson and the complete course when you enroll:
- 🔓 Full lesson videos with no limits
- 💻 Access to the final source code
- 🎓 Course progress tracking & completion
- 💬 Invite to our private Discord community
One-time payment. Lifetime updates included.