gpt4 book ai didi

javascript - 如何在动画元素 onScroll 时获得准确的滚动位置

转载 作者:行者123 更新时间:2023-12-04 10:34:54 27 4
gpt4 key购买 nike

我正在尝试根据元素在场景中的进展在滚动时为元素设置动画。我遇到了浏览器返回间歇性滚动位置的问题,这使得在启动和停止元素动画时很难准确。

最小的例子:

fiddle Fiddle Demo

const tweens = document.querySelectorAll('.tween');
const trigger = document.querySelector('.start');
const triggerRect = trigger.getBoundingClientRect();

let yScroll = window.scrollY;
let yCurrent = yScroll;
let AF = null;

const start = triggerRect.top - yScroll - 200;
const end = start + 400;

const updateScroll = () => {
yScroll = window.scrollY;
startAnimation();
}

const startAnimation = () => {
if(!AF) AF = requestAnimationFrame(animate)
}

const cancelAnimation = () => {
yCurrent = yScroll;
cancelAnimationFrame(AF);
AF = null;
}

const animate = () => {
if(yCurrent === yScroll) cancelAnimation();
else {
updateElements();
yCurrent = yScroll;
AF = requestAnimationFrame(animate);
}
}

const updateElements = () => {
const pos = yCurrent - start;
if(inScene()){
tweens[0].style.transform = `translateX(${pos}px)`;
tweens[1].style.transform = `translateY(${pos}px)`;
}
}

const inScene = () => {
return start <= yCurrent && end >= yCurrent ? true : false;
};


window.addEventListener('scroll', updateScroll);
.wrapper{
position:relative;
margin: 100vh 20px;
background: rgb(240,240,240);
height: 900px;
border: 1px solid red;
}

.line{
position:absolute;
left: 0;
width: 100%;
height: 1px;
background: red;
}

.start{
top: 200px;
}

.end{
bottom: 200px;
}

.tween{
position:absolute;
top:200px;
width: 100px;
height: 100px;
background: blue;
}

.left{
left: 0;
}

.right{
right: 0;
}
<h1>Scroll Down</h1>
<div class="wrapper">
<div class="line start trigger"></div>
<div class="line end"></div>
<div class="tween left"></div>
<div class="tween right"></div>
</div>

如您所见,元素应该停在直线上,但当您滚动时,它们从来没有真正停止过。滚动得越快,情况就越糟糕。

那么有没有一种技术可以返回正确的滚动位置或以某种方式消除元素的抖动,从而在滚动时可以达到整个范围,而不是不断地低于预期位置?

我知道这是可能的,因为像 ScrollMagic 这样的滚动库可以很好地处理这个问题,但我真的不想解构整个 ScrollMagic 框架以了解它们是如何实现的。我会使用 ScrollMagic 框架本身,但我正在尝试使用动量样式的滚动容器来包装页面并将其与此容器内的元素一起滚动滚动并使用 ScrollMagic 它是非常有问题的。所以我想我会在这里发布问题,看看是否有人对这种情况有任何经验或见解。

任何指导将不胜感激,因为我已经考虑了一段时间。

最佳答案

让我们假设浏览器就是这样,并不是所有经过的像素都会导致事件。您最终会得到远离末尾的元素,因为您检查滚动位置是否“在场景中”。当它是之前的 5 倍时 - 没关系。接下来是 5px 之后 - 你忽略它。您可以做的是,每当您滚动到场景外而不是忽略它时,将对象动画化到它们的最终位置。

所以只是为了开始它,我会改变这个:

const updateElements = () => {
let pos = yCurrent - start;
pos = Math.min(400, Math.max(0, pos));
tweens[0].style.transform = `translateX(${pos}px)`;
tweens[1].style.transform = `translateY(${pos}px)`;
}

可以进一步优化,使其在“场景”之外时只启动一次动画。如果您对此也有疑问,请告诉我。

更新:

这是仅在需要时才进行动画处理的版本:

const updateElements = () => {
let pos = yCurrent - start;
pos = Math.min(400, Math.max(0, pos));
const styles = [...tweens].map(tween => window.getComputedStyle(tween, null));
const transforms = styles.map(style => new WebKitCSSMatrix(style.getPropertyValue('transform')));
if (transforms[0].m41 !== pos) {
tweens[0].style.transform = `translateX(${pos}px)`;
}

if (transforms[1].m42 !== pos) {
tweens[1].style.transform = `translateY(${pos}px)`;
}
}

阅读 translate 是 hell ,所以如果我们只关心 Webkit 浏览器,我们可以使用 WebKitCSSMatrix,但 Firefox 没有类似的东西,所以你可以使用 external

我同意 artanik 它在没有 requestAnimationFrame 的情况下工作得更好

关于javascript - 如何在动画元素 onScroll 时获得准确的滚动位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60231683/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com