mirror of
https://github.com/flarum/framework.git
synced 2025-02-06 14:07:32 +08:00
Optimize ScrollListener performance
Listen to "scroll" event and throttle callback executions instead of actively polling for changes to the scroll position. Fixes #1222.
This commit is contained in:
parent
ef38660f08
commit
cf16b6c20b
|
@ -1,4 +1,4 @@
|
||||||
const scroll = window.requestAnimationFrame ||
|
const later = window.requestAnimationFrame ||
|
||||||
window.webkitRequestAnimationFrame ||
|
window.webkitRequestAnimationFrame ||
|
||||||
window.mozRequestAnimationFrame ||
|
window.mozRequestAnimationFrame ||
|
||||||
window.msRequestAnimationFrame ||
|
window.msRequestAnimationFrame ||
|
||||||
|
@ -17,7 +17,7 @@ export default class ScrollListener {
|
||||||
*/
|
*/
|
||||||
constructor(callback) {
|
constructor(callback) {
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.lastTop = -1;
|
this.ticking = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,27 +27,27 @@ export default class ScrollListener {
|
||||||
* @protected
|
* @protected
|
||||||
*/
|
*/
|
||||||
loop() {
|
loop() {
|
||||||
if (!this.active) return;
|
// THROTTLE: If the callback is still running (or hasn't yet run), we ignore
|
||||||
|
// further scroll events.
|
||||||
|
if (this.ticking) return;
|
||||||
|
|
||||||
this.update();
|
// Schedule the callback to be executed soon (TM), and stop throttling once
|
||||||
|
// the callback is done.
|
||||||
|
later(() => {
|
||||||
|
this.update();
|
||||||
|
this.ticking = false;
|
||||||
|
});
|
||||||
|
|
||||||
scroll(this.loop.bind(this));
|
this.ticking = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the scroll position has changed; if it has, run the handler.
|
* Run the callback, whether there was a scroll event or not.
|
||||||
*
|
*
|
||||||
* @param {Boolean} [force=false] Whether or not to force the handler to be
|
|
||||||
* run, even if the scroll position hasn't changed.
|
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
update(force) {
|
update() {
|
||||||
const top = window.pageYOffset;
|
this.callback(window.pageYOffset);
|
||||||
|
|
||||||
if (this.lastTop !== top || force) {
|
|
||||||
this.callback(top);
|
|
||||||
this.lastTop = top;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,8 +57,10 @@ export default class ScrollListener {
|
||||||
*/
|
*/
|
||||||
start() {
|
start() {
|
||||||
if (!this.active) {
|
if (!this.active) {
|
||||||
this.active = true;
|
window.addEventListener(
|
||||||
this.loop();
|
'scroll',
|
||||||
|
this.active = this.loop.bind(this)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,6 +70,8 @@ export default class ScrollListener {
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
stop() {
|
stop() {
|
||||||
this.active = false;
|
window.removeEventListener('scroll', this.active);
|
||||||
|
|
||||||
|
this.active = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import Component from '../../common/Component';
|
||||||
import ScrollListener from '../../common/utils/ScrollListener';
|
import ScrollListener from '../../common/utils/ScrollListener';
|
||||||
import PostLoading from './LoadingPost';
|
import PostLoading from './LoadingPost';
|
||||||
import anchorScroll from '../../common/utils/anchorScroll';
|
import anchorScroll from '../../common/utils/anchorScroll';
|
||||||
import mixin from '../../common/utils/mixin';
|
|
||||||
import evented from '../../common/utils/evented';
|
import evented from '../../common/utils/evented';
|
||||||
import ReplyPlaceholder from './ReplyPlaceholder';
|
import ReplyPlaceholder from './ReplyPlaceholder';
|
||||||
import Button from '../../common/components/Button';
|
import Button from '../../common/components/Button';
|
||||||
|
@ -586,7 +585,7 @@ class PostStream extends Component {
|
||||||
*/
|
*/
|
||||||
unpause() {
|
unpause() {
|
||||||
this.paused = false;
|
this.paused = false;
|
||||||
this.scrollListener.update(true);
|
this.scrollListener.update();
|
||||||
this.trigger('unpaused');
|
this.trigger('unpaused');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ import Component from '../../common/Component';
|
||||||
import icon from '../../common/helpers/icon';
|
import icon from '../../common/helpers/icon';
|
||||||
import ScrollListener from '../../common/utils/ScrollListener';
|
import ScrollListener from '../../common/utils/ScrollListener';
|
||||||
import SubtreeRetainer from '../../common/utils/SubtreeRetainer';
|
import SubtreeRetainer from '../../common/utils/SubtreeRetainer';
|
||||||
import computed from '../../common/utils/computed';
|
|
||||||
import formatNumber from '../../common/utils/formatNumber';
|
import formatNumber from '../../common/utils/formatNumber';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -365,7 +364,7 @@ export default class PostStreamScrubber extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
onresize() {
|
onresize() {
|
||||||
this.scrollListener.update(true);
|
this.scrollListener.update();
|
||||||
|
|
||||||
// Adjust the height of the scrollbar so that it fills the height of
|
// Adjust the height of the scrollbar so that it fills the height of
|
||||||
// the sidebar and doesn't overlap the footer.
|
// the sidebar and doesn't overlap the footer.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user