javascript - 根据滚动位置沿路径绝对定位元素
问题描述
我正在尝试将 div 元素定位在用作其路径的正弦波上。当用户滚动时,回调应该能够计算正弦波的left
和top
属性。Ball
我的定位有问题。我正在使用Math.abs
y 轴,并添加 8(或 -8)个像素来处理 x 轴。
我注意到的另一件事是滚动事件侦听器回调有时会错过某些断点。我已经控制台记录了滚动位置及其真实情况,回调要么每 3 个像素执行一次,要么浏览器scroll
出于某种原因自行限制事件(我可以理解,跟踪每个像素滚动没有意义)。
无论如何,我想知道为什么我目前的方法不起作用,是否有更好的解决方案来解决这个问题?我觉得事情太多了,这可以通过更好的方式实现。这是我所拥有的:
import React from "react";
import styled from "styled-components";
const lineHeight = 200;
export default React.memo(() => {
const [top, setTop] = React.useState(275);
const [left, setLeft] = React.useState(0);
const [previousPosition, setPreviousPosition] = React.useState(0);
React.useEffect(() => { const s = skrollr.init() }, []);
React.useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [previousPosition, left]);
const handleScroll = React.useCallback(() => {
const pageYOffset = window.pageYOffset;
const isMovingForward = pageYOffset > previousPosition;
setPreviousPosition(window.pageYOffset);
setTop(lineHeight - Math.abs(lineHeight - pageYOffset));
if (isMovingForward) {
if (pageYOffset > 575 && pageYOffset <= 770) setLeft(left + 8);
} else {
if (pageYOffset <= 770 && pageYOffset >= 575) setLeft(left - 8)
}
}, [previousPosition, left]);
return (
<Main>
<Container
data-500p="transform: translateX(0%)"
data-1000p="transform: translateX(-800%)"
>
<Content>
<WaveContainer>
<Wave src="https://www.designcrispy.com/wp-content/uploads/2017/11/Sine-Wave-Curve.png" />
</WaveContainer>
<BallContainer top={top} left={left}>
<Ball />
</BallContainer>
</Content>
</Container>
</Main>
);
});
const Main = styled.div`
margin: 0;
padding: 0;
box-sizing: border-box;
`;
const Container = styled.div`
position: fixed;
width: 100%;
display: flex;
top: 0;
left: 0;
`;
const Content = styled.div`
min-width: 100vw;
height: auto;
display: grid;
place-items: center;
height: 100vh;
background: #fffee1;
font-weight: 900;
position: relative;
`;
const Wave = styled.img`
width: 600px;
`;
const WaveContainer = styled.div`
position: absolute;
left: -40px;
top: 45%;
`;
const Ball = styled.div`
width: 20px;
height: 20px;
border-radius: 50%;
background: black;
`;
const BallContainer = styled.div`
position: absolute;
transition: 0.25s;
${({ top, left }) => `top: ${top}px; left: ${left}px;`};
`;
我正在使用Skrollr来处理固定的画布 + 滚动长度。
解决方案
我更改了您的代码沙箱,所以它可以满足您的需要:https ://codesandbox.io/s/determined-nobel-64odf (我希望)
我应该补充一点,我更改了有关您的代码的各种内容:
- 每次左侧或先前位置更改时,无需设置新的滚动侦听器。关于先前位置和决定页面是向上还是向下滚动的所有代码是什么?我删除了它。
- 动画由于过渡而被限制:在您的 Ball 容器上为 0.25 秒。为了计算球相对于图像的位置 - 正弦波,我将它们移动到同一个容器中。
- 要计算球的确切位置,需要使用 WAVE_WIDTH 和 WAVE_HEIGHT 常量,并且需要使用适当的数学 - 图像上的正弦曲线似乎很长,为 2,5 个周期。然而 2,58 更好地适应动画。我会尝试使用不同的正弦波并弄清楚。
推荐阅读
- javascript - javascript scrollIntoView 函数在我的全局事件侦听器中不起作用
- javascript - 如何将 DOM 数据转换为 json
- html - 圆形元素上的框阴影
- asp.net-core - Kubernetes:向环境添加入口内部 ip
- python - 在执行期间更改 conda 环境
- javafx - 如何在舞台中居中放置场景
- java - 如何在 SharedPreferences 中保存 graphics.Path 变量
- c - 子进程如何杀死其他子进程然后终止?
- python - rtx 2070s 无法从设备分配 gpu 内存:CUDA_ERROR_OUT_OF_MEMORY:内存不足
- php - 无法让 PHP 将表单数据处理到 MySQL 数据库中