我在开始收听滚动事件之前正在更新元素的scrollTop
。但是,滚动事件会触发,即使在 scrollTop
更新后添加了。
我注意到,如果我将.onscroll
作业包裹在setTimeout(..., 1);
中,那就可以了。
另请注意,在输出中,内存中的scrollTop
值不会更改,但会触发事件。
从0开始
尚未添加监听器100
听众添加了100
滚动100
任何人都可以解释为什么这样的作品?使用setTimeout
或设置标志似乎是一种解决这个问题的方法;有更好的方法吗?
var div = document.getElementsByTagName('div')[0];
console.log("starting out", div.scrollTop);
div.scrollTop = 100;
console.log("haven't added listener yet", div.scrollTop);
div.onscroll = function() {
console.log('scrolled', div.scrollTop);
};
console.log("listener added", div.scrollTop);

div {
width: 80%;
height: 200px;
margin: 20px auto;
overflow: auto;
padding: 20px;
box-sizing: border-box;
border: 1px solid black;
}

<div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi id mi sit amet tortor suscipit sagittis at id risus. Nullam ultricies nisi ac tortor ultrices porta. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nam purus sapien, efficitur in risus non, cursus egestas lectus. Curabitur pharetra erat sapien, et malesuada neque mollis nec. Donec dolor lacus, pretium eu ipsum sit amet, placerat vehicula orci. Sed viverra metus id magna sodales, et condimentum urna sagittis. Donec a viverra urna. Pellentesque lacinia commodo ligula sed porttitor. Aliquam iaculis diam nec nibh congue congue. Nunc eget dapibus orci, ac tristique nunc. Mauris nisl tellus, posuere sed lectus sit amet, vulputate sollicitudin magna. Nullam porttitor leo bibendum, varius libero vitae, ultrices diam. Donec mauris nulla, egestas non nisi sit amet, ultricies laoreet sapien.</p>
<p>Vivamus mollis placerat felis ut porta. Pellentesque pellentesque blandit leo, fermentum sollicitudin risus porta quis. Phasellus gravida justo nec mi accumsan, in euismod tortor venenatis. Donec porttitor consequat dui ac iaculis. Quisque scelerisque dictum risus, eu gravida nibh sodales in. Vivamus sit amet consectetur urna. Aliquam quis pretium turpis, non rhoncus lectus. Ut vel mi urna. Mauris interdum congue felis ut faucibus. Praesent nec lobortis enim. Vestibulum velit nisl, dapibus vulputate interdum vitae, sagittis a nisl.</p>
<p>Donec consectetur justo a purus sodales, quis ultrices enim sodales. Sed fermentum congue enim vehicula volutpat. Proin pellentesque elit et dolor congue, in blandit tellus aliquet. Cras tincidunt metus lorem, et tincidunt arcu condimentum eget. Curabitur sed ipsum nec erat mollis volutpat eget eget purus. Nam nec eleifend est. Sed ut elit eget odio mollis dignissim vitae nec urna. In vel libero eget libero rutrum consectetur non eget dui. Proin dignissim convallis elit, id mollis metus sodales eget. Aliquam non iaculis justo. Aenean vel diam nibh. Nam euismod viverra ante, ac molestie sem. Donec cursus justo a sagittis iaculis. Sed at maximus lacus, sit amet gravida mauris. Curabitur non odio at ipsum consequat fermentum. Morbi vestibulum nec dui id tincidunt.</p>
<p>Integer nec nunc ultricies, mattis leo sed, gravida enim. In hac habitasse platea dictumst. Nunc sed turpis sed nisi consequat faucibus. Fusce sagittis maximus luctus. Maecenas at tortor blandit, imperdiet ligula vel, vestibulum diam. Proin consequat sodales nisl, quis varius erat semper vitae. Etiam ac pretium lacus. Phasellus in vestibulum tellus, nec tempus dolor. Etiam fringilla convallis rhoncus. Sed id enim erat. Integer congue orci sapien, ac porttitor arcu pellentesque eget. Mauris eu rutrum urna. Donec ante eros, scelerisque id ipsum et, pulvinar dapibus erat.</p>
<p>Fusce eget bibendum eros. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Donec finibus justo a neque hendrerit, imperdiet fringilla nibh tincidunt. Etiam consequat a erat fringilla volutpat. Proin porttitor nec sem non semper. Suspendisse sollicitudin erat eu urna gravida volutpat quis sit amet leo. Mauris luctus purus eget purus mattis semper. Curabitur ut ante fringilla, porta neque non, hendrerit diam. Morbi dignissim congue orci ac vestibulum. Vestibulum ipsum urna, faucibus nec venenatis eu, efficitur vitae massa. Suspendisse lectus lorem, molestie vel consequat eget, malesuada sed turpis. Curabitur sit amet ipsum et justo sollicitudin pretium. Praesent dignissim, mauris ut hendrerit egestas, massa orci cursus justo, non porta metus erat et velit. Curabitur vitae orci eu erat ultrices aliquet.</p>
</div>
&#13;
答案 0 :(得分:0)
我之所以说是因为浏览器在下一帧之前没有进行实际滚动。因此,在滚动甚至更新之前设置事件监听器。
你可以做些什么来避免它,忽略第一个滚动事件。
var scrolled = false;
window.scrollTo(0, 100);
window.addEventListener('scroll', function() {
if(!scrolled) {
scrolled = true;
return;
}
// Do stuff...
});
编辑以反映OP的评论:
我无法想象为什么这对你不起作用:
window.scrollTo(0, 100);
window.addEventListener('scroll', function() {
if(typeof window.scrollEventHasFired === "undefined") {
window.scrollEventHasFired = true;
return;
}
// Do stuff...
});
进一步修改,反映新信息:
这对你有用吗?这允许设置多个事件,并允许在事件之外调用侦听器: var scrolled = [false], id = 0;
var listener = function(skipFirstExec, listenerId, args...) {
if(skipFirstExec && !scrolled[listenerId]) {
scrolled[listenerId] = true;
return;
}
// Do stuff
};
window.addEventListener('scroll', listener.bind(thisArg, true, ++id));
scrolled[id] = false;
window.addEventListener('scroll', listener.bind(thisArg, false, ++id)); // This one won't skip the scroll
scrolled[id] = false;
window.addEventListener('scroll', listener.bind(thisArg, true, ++id));
scrolled[id] = false;
listener(false, 0, args...); // call listener outside of event
最终修改:
这对我有用,不知道为什么我之前没有想到这个:
/**
* requestAnimationFrame polyfill by Erik Möller & Paul Irish et. al.
* https://gist.github.com/1866474
*
* http://paulirish.com/2011/requestanimationframe-for-smart-animating/
* http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
**/
/*jshint asi: false, browser: true, curly: true, eqeqeq: true, forin: false, newcap: true, noempty: true, strict: true, undef: true */
(function( window ) {
'use strict';
var lastTime = 0;
var prefixes = 'webkit moz ms o'.split(' ');
// get unprefixed rAF and cAF, if present
var requestAnimationFrame = window.requestAnimationFrame;
var cancelAnimationFrame = window.cancelAnimationFrame;
// loop through vendor prefixes and get prefixed rAF and cAF
var prefix;
for( var i = 0; i < prefixes.length; i++ ) {
if ( requestAnimationFrame && cancelAnimationFrame ) {
break;
}
prefix = prefixes[i];
requestAnimationFrame = requestAnimationFrame || window[ prefix + 'RequestAnimationFrame' ];
cancelAnimationFrame = cancelAnimationFrame || window[ prefix + 'CancelAnimationFrame' ] ||
window[ prefix + 'CancelRequestAnimationFrame' ];
}
// fallback to setTimeout and clearTimeout if either request/cancel is not supported
if ( !requestAnimationFrame || !cancelAnimationFrame ) {
requestAnimationFrame = function( callback, element ) {
var currTime = new Date().getTime();
var timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) );
var id = window.setTimeout( function() {
callback( currTime + timeToCall );
}, timeToCall );
lastTime = currTime + timeToCall;
return id;
};
cancelAnimationFrame = function( id ) {
window.clearTimeout( id );
};
}
// put in global namespace
window.requestAnimationFrame = requestAnimationFrame;
window.cancelAnimationFrame = cancelAnimationFrame;
})( window );
(function() {
var div = document.getElementsByTagName('div')[0];
console.log("starting out", div.scrollTop);
div.scrollTop = 100;
console.log("haven't added listener yet", div.scrollTop);
window.requestAnimationFrame(function() {
div.onscroll = function() {
console.log('scrolled', div.scrollTop);
};
console.log("listener added", div.scrollTop);
});
})();