Sus*_*pta 21 javascript scroll js-scrollintoview
我使用的是Javascript方法Element.scrollIntoView()
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
滚动结束时有什么办法可以让我知道.说有动画,或者我已经设定了{behavior: smooth}.
我假设滚动是异步的,并想知道是否有任何回调像它的机制.
Her*_*ine 13
我偶然发现了这个问题,因为我想在滚动完成后集中特定的输入(以便保持平滑滚动)。
如果您有与我相同的用例,您实际上不需要等待滚动完成来集中输入,您可以简单地禁用 focus 的滚动。
其实现方式如下:
window.scrollTo({ top: 0, behavior: "smooth" });
myInput.focus({ preventScroll: true });
Run Code Online (Sandbox Code Playgroud)
比照: https: //github.com/w3c/csswg-drafts/issues/3744#issuecomment-685683932
顺便说一句,这个特定问题(在执行操作之前等待滚动完成)在 CSSWG GitHub 中讨论:https://github.com/w3c/csswg-drafts/issues/3744
gue*_*314 12
您可以使用IntersectionObserver,检查是否元素.isIntersecting在IntersectionObserver回调函数
const element = document.getElementById("box");
const intersectionObserver = new IntersectionObserver((entries) => {
let [entry] = entries;
if (entry.isIntersecting) {
setTimeout(() => alert(`${entry.target.id} is visible`), 100)
}
});
// start observing
intersectionObserver.observe(box);
element.scrollIntoView({behavior: "smooth"});Run Code Online (Sandbox Code Playgroud)
body {
height: calc(100vh * 2);
}
#box {
position: relative;
top:500px;
}Run Code Online (Sandbox Code Playgroud)
<div id="box">
box
</div>Run Code Online (Sandbox Code Playgroud)
Kai*_*ido 12
对于这种“平滑”行为,所有规范都说的是
当用户代理是执行滚动盒框位置的平滑滚动,它必须更新框的滚动位置的用户代理定义的方式在用户代理定义的时间量。
(强调我的)
因此,不仅没有单个事件在完成后会触发,而且我们甚至无法假设不同浏览器之间的任何稳定行为。
事实上,当前的 Firefox 和 Chrome 的行为已经有所不同:
因此,这已经取消了针对此问题的所有基于超时的解决方案的资格。
现在,这里的一个答案建议使用 MutationObserver,这不是一个太糟糕的解决方案,但它不太便携,并且没有考虑inline和block选项。
所以最好的办法实际上可能是定期检查我们是否停止滚动。为了以非侵入性的方式做到这一点,我们可以启动一个requestAnimationFrame动力循环,这样我们的检查每帧只执行一次。
这里有一个这样的实现,它将返回一个 Promise,一旦滚动操作完成,该 Promise 将得到解决。
注意:这段代码遗漏了一种检查操作是否成功的方法,因为如果页面上发生了其他滚动操作,所有当前的滚动操作都会被取消,但我将把它作为读者的练习。
const buttons = [ ...document.querySelectorAll( 'button' ) ];
document.addEventListener( 'click', ({ target }) => {
// handle delegated event
target = target.closest('button');
if( !target ) { return; }
// find where to go next
const next_index = (buttons.indexOf(target) + 1) % buttons.length;
const next_btn = buttons[next_index];
const block_type = target.dataset.block;
// make it red
document.body.classList.add( 'scrolling' );
smoothScroll( next_btn, { block: block_type })
.then( () => {
// remove the red
document.body.classList.remove( 'scrolling' );
} )
});
/*
*
* Promised based scrollIntoView( { behavior: 'smooth' } )
* @param { Element } elem
** ::An Element on which we'll call scrollIntoView
* @param { object } [options]
** ::An optional scrollIntoViewOptions dictionary
* @return { Promise } (void)
** ::Resolves when the scrolling ends
*
*/
function smoothScroll( elem, options ) {
return new Promise( (resolve) => {
if( !( elem instanceof Element ) ) {
throw new TypeError( 'Argument 1 must be an Element' );
}
let same = 0; // a counter
let lastPos = null; // last known Y position
// pass the user defined options along with our default
const scrollOptions = Object.assign( { behavior: 'smooth' }, options );
// let's begin
elem.scrollIntoView( 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 = elem.getBoundingClientRect().top;
if( newPos === lastPos ) { // same as previous
if(same ++ > 2) { // if it's more than two frames
/* @todo: verify it succeeded
* if(isAtCorrectPosition(elem, options) {
* resolve();
* } else {
* reject();
* }
* return;
*/
return resolve(); // we've come to an halt
}
}
else {
same = 0; // reset our counter
lastPos = newPos; // remember our current position
}
// check again next painting frame
requestAnimationFrame(check);
}
});
}Run Code Online (Sandbox Code Playgroud)
p {
height: 400vh;
width: 5px;
background: repeat 0 0 / 5px 10px
linear-gradient(to bottom, black 50%, white 50%);
}
body.scrolling {
background: red;
}Run Code Online (Sandbox Code Playgroud)
<button data-block="center">scroll to next button <code>block:center</code></button>
<p></p>
<button data-block="start">scroll to next button <code>block:start</code></button>
<p></p>
<button data-block="nearest">scroll to next button <code>block:nearest</code></button>
<p></p>
<button>scroll to top</button>Run Code Online (Sandbox Code Playgroud)
没有scrollEnd事件,但是您可以侦听scroll事件并检查事件是否仍在滚动窗口:
var scrollTimeout;
addEventListener('scroll', function(e) {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(function() {
console.log('Scroll ended');
}, 100);
});
Run Code Online (Sandbox Code Playgroud)
小智 5
适用于我的 rxjs 解决方案
语言:打字稿
scrollToElementRef(
element: HTMLElement,
options?: ScrollIntoViewOptions,
emitFinish = false,
): void | Promise<boolean> {
element.scrollIntoView(options);
if (emitFinish) {
return fromEvent(window, 'scroll')
.pipe(debounceTime(100), first(), mapTo(true)).toPromise();
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
const element = document.getElementById('ELEM_ID');
scrollToElementRef(elment, {behavior: 'smooth'}, true).then(() => {
// scroll finished do something
})
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8773 次 |
| 最近记录: |