Javascript 如何根据当前页面偏移和上一页偏移计算动画的速度(以秒为单位)?

Javascript 如何根据当前页面偏移和上一页偏移计算动画的速度(以秒为单位)?,javascript,reactjs,styled-components,Javascript,Reactjs,Styled Components,我正在尝试基于用户交互来旋转轮子。如果用户正在加速滚动,滚轮应该旋转得更快。同样,如果用户正在减速滚动,滚轮应该停止。我正在使用Skrollr库对样式化组件和React状态应用这些条件 以下是我所拥有的: import React from "react"; import styled, { createGlobalStyle, css, keyframes } from "styled-components"; export default funct

我正在尝试基于用户交互来旋转轮子。如果用户正在加速滚动,滚轮应该旋转得更快。同样,如果用户正在减速滚动,滚轮应该停止。我正在使用Skrollr库对样式化组件和React状态应用这些条件

以下是我所拥有的:

import React from "react";
import styled, { createGlobalStyle, css, keyframes } from "styled-components";

export default function App() {
  const [previousPosition, setPreviousPosition] = React.useState(0);
  const [previousDelta, setPreviousDelta] = React.useState(0);
  const [speed, setSpeed] = React.useState(1);
  const [isStopping, setIsStopping] = React.useState(false);

  React.useEffect(() => {
    skrollr.init();

    window.addEventListener("scroll", handleScroll);

    return () => window.removeEventListener("scroll", handleScroll);
  }, [previousPosition, previousDelta]);

  const handleScroll = React.useCallback(() => {
    // get delta
    const delta = window.pageYOffset - previousPosition;

    if (previousDelta > delta) {
      // is stopping
      setIsStopping(true);
      setSpeed(0);
    } else {
      // is accelerating

      // calculate delta as a percentage
      const deltaAsPercentage = (delta / previousPosition) * 100;
      console.log("deltaAsPercentage", deltaAsPercentage);

      setIsStopping(false);
      setSpeed(deltaAsPercentage);
    }

    setPreviousPosition(window.pageYOffset);
  }, [previousPosition, previousDelta]);

  return (
    <Container data-10000p="transform: translateX(0%)">
      <GlobalStyles />
      <WheelContainer speed={speed} isStopping={isStopping}>
        <Image src="wheel.png" alt="wheel" />
      </WheelContainer>
    </Container>
  );
}

const Container = styled.div`
  position: fixed;
  width: 100%;
  display: flex;
  top: 0;
  left: 0;
`;

const spinForward = keyframes`
    0% {
        transform: rotateZ(0deg);
    }
    50% {
        transform: rotateZ(180deg);
    }
    100% {
        transform: rotateZ(360deg);
    }
`;

const stopWheel = keyframes`
    0% {
        transform: rotateZ(0deg);
    }
    100% {
        transform: rotateZ(360deg);
    }
`;

const WheelContainer = styled.div`
  ${({ speed, isStopping }) =>
    isStopping
      ? css`
          animation: ${stopWheel} 1s ease-out;
        `
      : css`
          animation: ${speed
            ? css`
                ${spinForward} ${speed}s linear infinite
              `
            : ""};
        `}
`;

const Image = styled.img``;

const GlobalStyles = createGlobalStyle`
    * {
        &::-webkit-scrollbar {
            display: none;
        }
    }
`;
从“React”导入React;
从“样式化组件”导入样式化,{createGlobalStyle,css,keyframes};
导出默认函数App(){
const[previousPosition,setPreviousPosition]=React.useState(0);
const[previousDelta,setPreviousDelta]=React.useState(0);
常数[速度,设定速度]=反应。使用状态(1);
常量[isStopping,setIsStopping]=React.useState(false);
React.useffect(()=>{
skrollr.init();
window.addEventListener(“滚动”,handleScroll);
return()=>window.removeEventListener(“滚动”,handleScroll);
},[previousPosition,previousDelta]);
const handleScroll=React.useCallback(()=>{
//得到三角洲
常量增量=window.pageYOffset-上一个位置;
如果(以前的增量>增量){
//正在停止
setIsStopping(真);
设定速度(0);
}否则{
//正在加速
//以百分比计算增量
常量deltaAsPercentage=(增量/先前位置)*100;
log(“deltaAsPercentage”,deltaAsPercentage);
setIsStopping(假);
设置速度(deltaAsPercentage);
}
setPreviousPosition(window.pageYOffset);
},[previousPosition,previousDelta]);
返回(
);
}
const Container=styled.div`
位置:固定;
宽度:100%;
显示器:flex;
排名:0;
左:0;
`;
常量向前旋转=关键帧`
0% {
变换:旋转(0度);
}
50% {
变换:旋转(180度);
}
100% {
变换:旋转(360度);
}
`;
const stopWheel=关键帧`
0% {
变换:旋转(0度);
}
100% {
变换:旋转(360度);
}
`;
const WheelContainer=styled.div`
${({speed,isStopping})=>
isStopping
?css`
动画:${stopWheel}1放松;
`
:css`
动画:${speed
?css`
${spinForward}${speed}的线性无限
`
: ""};
`}
`;
const Image=styled.img``;
const GlobalStyles=createGlobalStyle`
* {
&:-webkit滚动条{
显示:无;
}
}
`;
我数学不太好,所以我在用我所知道的尽我所能

我在scroll上做的第一件事是确定车轮是否应该停止或加速。如果它停止,我会改变组件的状态,让
wheelcainer
知道它应该调出当前动画。如果轮子不应该停止,我将保持当前动画并改变旋转速度

不管怎么说,我已经开始工作了。我遇到的问题是,它无法识别“较慢的滚动”。例如,用户可以快速或缓慢地滚动,但仍然可以滚动。缓慢的滚动不一定意味着它应该停止

另一个问题是,
spinBack
似乎永远不会被调用。即使是这样,我也不知道如何区分“较慢”的滚动和向后旋转

最后,我应该注意到,加速滚动似乎只有在mac的触摸板上才能识别。我只是插入了一个外部鼠标来测试它,但它并没有像预期的那样旋转

除此之外,我觉得还有更好的方法。也许是一些关于
Math.sin
Math.cos
的东西,或者类似的东西,我应该在高中数学课上更加注意。这个组件感觉太笨重了,因为它似乎有一个更简单的方法

这是一个沙箱

以下是我的尝试:

对我来说,第一个问题是代码在输入时执行。感觉函数计算需要一些小的时间延迟。 我们将使用
setTimeout
来实现这一点

第二:是的,你说得对。我们需要一个类似数学/触发器的函数,对于非常小的值,该函数将给出一个接近于零的值,对于增加的值,该函数将给出一个接近于1的值

第三点是……嗯,这更像是个人的事情——我不确定这是否是故意的,但我注意到,一旦滚动到顶部(即
window.pageYOffset=0
),
回滚功能就不起作用了。
因此,我使用了
wheel
eventListener,而不是
scroll
eventListener——这样,我可以使用
deltaY
属性查看它的变化程度

第四,我将速度设置为时间所覆盖距离的函数

最后:CSS的速度一开始对我来说是违反直觉的-出于某种原因,值越高,旋转速度越慢!我一直在想到底出了什么问题,直到我意识到我愚蠢的错误!