React:超级简单的平滑滚动
设置
概述
最终文件结构
SmoothScroll.js
useWindowSize.js
Section.js
App.js
我一直想重新设计我的作品集,其中一个主要需求就是实现平滑滚动效果。所以,我用 React 开发了一个非常简单的平滑滚动效果,没有任何其他依赖项。
在这个博客里,我们将一起创建这个博客。那么,让我们马上开始吧。
设置
运行以下命令来设置 React 应用。
npx create-react-app smooth-scroll
cd smooth-scroll
yarn start
概述
所以,我们本质上是想让一个div元素沿Y轴方向延迟平移。
这个div元素将承载完整的SPA(单页应用程序),从而实现流畅的滚动效果。
<div className="parent">
<div ref={scrollingContainer}>
{/* The Complete App */}
</div>
</div
.parent{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
}
在这种设置下,带有 ref 的 div 元素scrollingContainer将沿 Y 轴方向平移。
请注意,class 为“parent”的 div 元素已设置为position: fixed。这一点至关重要,否则子 div 元素将只会向上平移,导致下方空间空白。
这样做实际上是在告诉浏览器,我们的整个应用程序是一个“宽度=100%”和“高度=100%”的固定容器,没有滚动条之类的东西。
稍后,我们将设置高度
标签等于“scrollingContainerdiv”,这样我们就可以滚动了。
在滚动时,我们将平移“ scrollingContainerdiv”。
如果这段话让你感到困惑,别担心。希望代码能让你更明白。
最终文件结构
SmoothScroll.js
创建一个文件,src/components/SmoothScroll/SmoothScroll.js并将以下代码粘贴到该文件中。
暂时不用担心导入语句,我们稍后会添加。
import React, { useEffect, useRef } from "react";
import "./SmoothScroll.css";
import useWindowSize from "../../hooks/useWindowSize";
const SmoothScroll = ({ children }) => {
// 1.
const windowSize = useWindowSize();
//2.
const scrollingContainerRef = useRef();
// 3.
const data = {
ease: 0.1,
current: 0,
previous: 0,
rounded: 0,
};
// 4.
useEffect(() => {
setBodyHeight();
}, [windowSize.height]);
const setBodyHeight = () => {
document.body.style.height = `${
scrollingContainerRef.current.getBoundingClientRect().height
}px`;
};
// 5.
useEffect(() => {
requestAnimationFrame(() => smoothScrollingHandler());
}, []);
const smoothScrollingHandler = () => {
data.current = window.scrollY;
data.previous += (data.current - data.previous) * data.ease;
data.rounded = Math.round(data.previous * 100) / 100;
scrollingContainerRef.current.style.transform = `translateY(-${data.previous}px)`;
// Recursive call
requestAnimationFrame(() => smoothScrollingHandler());
};
return (
<div className="parent">
<div ref={scrollingContainerRef}>{children}</div>
</div>
);
};
export default SmoothScroll;
让我们来详细分析一下。
- useWindowSize() 是一个自定义钩子,它返回窗口的当前 innerWidth 和 innerHeight。
- scrollingContainerRef 用于动态地将 translateY 属性应用于 div 元素。
data这不是一种状态,因为我们不希望每次滚动时 React 组件都重新渲染。- 此 useEffect 仅在
windowSize更改时(例如用户调整浏览器窗口大小)运行。setBodyHeight它将 height 属性设置为“div”的高度scrollingContainerRef。在将“position: fixed”传递给“父 div”后,这确保我们有足够的空间滚动浏览整个“scrollingContainerRefdiv”。 - 此 useEffect 仅运行一次并调用该
smoothScrolling函数。该函数递归运行,并在用户滚动页面时smoothScrolling更改“div”元素的 translate 属性。scrollingContainerRef
请注意,我们是smoothScrolling通过requestAnimationFrame()函数来调用该函数的。
该
window.requestAnimationFrame(**)**方法告知浏览器您希望执行动画,并请求浏览器在下次重绘之前调用指定的函数来更新动画。该方法接受一个回调函数作为参数,该回调函数将在重绘之前被调用。注意:
requestAnimationFrame()如果要在下次重绘时为另一帧添加动画, 则回调例程本身必须再次调用 。requestAnimationFrame()这是一次性操作。
SmoothScrolling.css
创建一个文件,src/components/SmoothScroll/SmoothScroll.css并将以下代码粘贴到该文件中。
.parent {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
pointer-events: none;
}
useWindowSize.js
在src/hooks/useWindowSize.js目录下创建文件,并将以下代码粘贴到该文件中。
import { useState, useEffect } from "react";
export default function useWindowSize() {
const getSize = () => {
return {
width: window.innerWidth,
height: window.innerHeight,
};
};
const [windowSize, setWindowSize] = useState(getSize);
useEffect(() => {
const handleResize = () => {
setWindowSize(getSize());
};
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowSize;
}
这是一个非常简单的钩子,它监听窗口的事件resize并返回窗口的最新innerWidth状态。innerHeight
Section.js
创建一个文件src/components/Section/Section.js,并将以下代码粘贴到该文件中。
import React from "react";
import "./section.css";
const section = ({ flexDirection }) => {
return (
<div className="section" style={{ flexDirection: flexDirection }}>
<div className="left-container">
<div className="block"></div>
</div>
<div className="right-container">
<div className="container">
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. In
laudantium esse fugiat illum tempore sapiente soluta labore voluptas
iusto deleniti ab suscipit dolores quisquam corrupti facilis, id
temporibus mollitia repellat omnis tempora commodi eveniet.
Incidunt, perspiciatis, adipisci laboriosam dolores quos dolor
voluptate odio magnam aperiam, alias asperiores pariatur! Nisi,
libero!
</p>
</div>
</div>
</div>
);
};
export default section;
SmoothScrolling.css
创建一个文件src/components/Section/Section.css,并将以下代码粘贴到该文件中。
.section {
display: flex;
justify-content: space-around;
width: 100%;
align-items: center;
height: 100vh;
}
.block {
width: 250px;
height: 250px;
padding: 60px;
background-color: peachpuff;
}
.container {
width: 500px;
}
p {
font-size: 1.5rem;
}
只是一个用来填充滚动容器中一些空间的 React 组件
App.js
import React from "react";
import "./App.css";
import Section from "./components/Section/Section";
import SmoothScroll from "./components/SmoothScroll/SmoothScroll";
function App() {
return (
<SmoothScroll>
<h2>Smooth Scrolling</h2>
<Section flexDirection="row" />
<Section flexDirection="row-reverse" />
<Section flexDirection="row" />
<Section flexDirection="row-reverse" />
<Section flexDirection="row" />
<Section flexDirection="row-reverse" />
</SmoothScroll>
);
}
export default App;
App.css
h2 {
text-align: center;
margin: 40px auto;
font-size: 4rem;
}
感谢阅读!
很想听听你的想法!
文章来源:https://dev.to/holdmypotion/react-super-simple-smooth-scrolling-2l08
