gpt4 book ai didi

javascript - 如何检测以 javascript 结束的窗口滚动?

转载 作者:行者123 更新时间:2023-12-01 00:12:09 25 4
gpt4 key购买 nike

我想在滚动结束后向所选元素添加一个类。如何在 JS 中检测滚动结束?

HTML

<ul class="list" id="wrapper">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li id="element">7</li>
<li>8</li>
<li>9</li>
<li>10</li>
</ul>

JS

const element = document.getElementById('element');
const y = element.getBoundingClientRect().top + window.scrollY;


window.scroll({
top: y,
behavior: 'smooth'
});

JSBIN EXAMPLE

最佳答案

2023 年更新:

现在有一个 scrollend event你可以听听。当滚动结束时,无论是用户滚动还是程序化平滑滚动结束,都会触发此事件。浏览器支持还不是很好,但应该很快就会在所有地方可用。

if (!("onscrollend" in window)) {
console.warn("Your browser doesn't support the onscrollend event");
}

const trigger = document.getElementById( 'trigger' );
const scroll_forcer = document.getElementById( 'scroll_forcer' );

let scrolling = false; // a simple flag letting us know if we're already scrolling
trigger.onclick = (evt) => startScroll();

function startScroll() {
setTimeout(()=> {
scroll_forcer.classList.add( "scrolling" )
document.scrollingElement.scrollTo( { top: 1000, behavior: "smooth" } );
document.addEventListener( "scrollend", (evt) => {
scroll_forcer.classList.remove( "scrolling" );
}, { once: true });
}, 10);
};
#scroll_forcer {
height: 5000vh;
background-image: linear-gradient(to bottom, red, green);
background-size: 100% 100px;
}
#scroll_forcer.scrolling {
filter: grayscale(70%);
}
<button id="trigger">click to scroll</button>
<div id="scroll_forcer">
</div>

所以暂时我可能还需要之前的答案:

<小时/>

本身没有事件可以告诉平滑滚动何时结束。

对于如何发生这种平滑滚动,也没有标准行为,没有定义的持续时间,没有定义的计时函数(Chrome 使用缓入输出函数,而 Firefox 使用线性函数),并且添加了一个平滑滚动可以是 canceled在中间通过对滚动算法的其他调用,甚至根本没有效果......

所以这个检测并不那么容易。

我目前发现的最好方法是启动 requestAnimationFrame如果我们的目标位于同一位置,则动力循环将检查每个绘画帧(right after滚动操作)。一旦它在同一位置超过两帧,我们就假设滚动结束。这时我们可以检查它是否成功,只需检查我们是否处于预期位置即可:

const trigger = document.getElementById( 'trigger' );
const scroll_forcer = document.getElementById( 'scroll_forcer' );

let scrolling = false; // a simple flag letting us know if we're already scrolling
trigger.onclick = (evt) => startScroll();

function startScroll() {
setTimeout(()=> {
scroll_forcer.classList.add( "scrolling" )
smoothScrollTo( { top: 1000 } )
.catch( (err) => {
/*
here you can handle when the smooth-scroll
gets disabled by an other scrolling
*/
console.error( 'failed to scroll to target' );
} )
// all done, lower the flag
.then( () => scroll_forcer.classList.remove( "scrolling" ) );
}, 10);
};


/*
*
* Promised based window.scrollTo( { behavior: 'smooth' } )
* @param { Element } elem
** ::An Element on which we'll call scrollIntoView
* @param { object } [options]
** ::An optional scrollToOptions dictionary
* @return { Promise } (void)
** ::Resolves when the scrolling ends
*
*/
function smoothScrollTo( options ) {
return new Promise( (resolve, reject) => {
const elem = document.scrollingElement;
let same = 0; // a counter

// last known scroll positions
let lastPos_top = elem.scrollTop;
let lastPos_left = elem.scrollLeft;

// pass the user defined options along with our default
const scrollOptions = Object.assign( {
behavior: 'smooth',
top: lastPos_top,
left: lastPos_left
}, options );

// expected final position
const maxScroll_top = elem.scrollHeight - elem.clientHeight;
const maxScroll_left = elem.scrollWidth - elem.clientWidth;
const targetPos_top = Math.max( 0, Math.min( maxScroll_top, scrollOptions.top ) );
const targetPos_left = Math.max( 0, Math.min( maxScroll_left, scrollOptions.left ) );

// let's begin
window.scrollTo( scrollOptions );
requestAnimationFrame( check );

// this function will be called every painting frame
// for the duration of the smooth scroll operation
function check() {
// check our current position
const newPos_top = elem.scrollTop;
const newPos_left = elem.scrollLeft;
// we add a 1px margin to be safe
// (can happen with floating values + when reaching one end)
const at_destination = Math.abs( newPos_top - targetPos_top) <= 1 &&
Math.abs( newPos_left - targetPos_left ) <= 1;
// same as previous
if( newPos_top === lastPos_top &&
newPos_left === lastPos_left ) {
if( same ++ > 2 ) { // if it's more than two frames
if( at_destination ) {
return resolve();
}
return reject();
}
}
else {
same = 0; // reset our counter
// remember our current position
lastPos_top = newPos_top;
lastPos_left = newPos_left;
}
// check again next painting frame
requestAnimationFrame( check );
}
});
}
#scroll_forcer {
height: 5000vh;
background-image: linear-gradient(to bottom, red, green);
background-size: 100% 100px;
}
#scroll_forcer.scrolling {
filter: grayscale(70%);
}
.as-console-wrapper {
max-height: calc( 50vh - 30px ) !important;
}
<button id="trigger">click to scroll</button>
<div id="scroll_forcer">
</div>

关于javascript - 如何检测以 javascript 结束的窗口滚动?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60000332/

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