diff --git a/src/index.js b/src/index.js index 6acc108..3c1b85a 100644 --- a/src/index.js +++ b/src/index.js @@ -53,6 +53,7 @@ export default class ScrollBehavior { this._checkWindowScrollHandle = null; this._windowScrollTarget = null; this._numWindowScrollAttempts = 0; + this._ignoreScrollEvents = false; this._scrollElements = {}; @@ -72,7 +73,9 @@ export default class ScrollBehavior { // It's fine to save element scroll positions here, though; the browser // won't modify them. - this._saveElementPosition(key); + if (!this._ignoreScrollEvents) { + this._saveElementPosition(key); + } }); }); } @@ -93,8 +96,8 @@ export default class ScrollBehavior { shouldUpdateScroll, savePositionHandle: null, - onScroll() { - if (!scrollElement.savePositionHandle) { + onScroll: () => { + if (!scrollElement.savePositionHandle && !this._ignoreScrollEvents) { scrollElement.savePositionHandle = requestAnimationFrame( saveElementPosition, ); @@ -103,7 +106,7 @@ export default class ScrollBehavior { }; // In case no scrolling occurs, save the initial position - if (!scrollElement.savePositionHandle) { + if (!scrollElement.savePositionHandle && !this._ignoreScrollEvents) { scrollElement.savePositionHandle = requestAnimationFrame( saveElementPosition, ); @@ -168,7 +171,20 @@ export default class ScrollBehavior { this._removeTransitionHook(); } + startIgnoringScrollEvents() { + this._ignoreScrollEvents = true; + } + + stopIgnoringScrollEvents() { + this._ignoreScrollEvents = false; + } + _onWindowScroll = () => { + if (this._ignoreScrollEvents) { + // Don't save the scroll position until the transition is complete + return; + } + // It's possible that this scroll operation was triggered by what will be a // `POP` transition. Instead of updating the saved location immediately, we // have to enqueue the update, then potentially cancel it if we observe a diff --git a/test/ScrollBehavior.test.js b/test/ScrollBehavior.test.js index 98eff09..df2d8f3 100644 --- a/test/ScrollBehavior.test.js +++ b/test/ScrollBehavior.test.js @@ -122,6 +122,34 @@ describe('ScrollBehavior', () => { ]); }); + it('should ignore scroll events when startIgnoringScrollEvents is used', done => { + const history = withRoutes(withScroll(createHistory())); + + unlisten = run(history, [ + () => { + history.startIgnoringScrollEvents(); + scrollTop(window, 5000); + delay(() => history.push('/detail')); + }, + () => { + delay(() => history.goBack()); + }, + () => { + expect(scrollTop(window)).to.equal(0); + history.stopIgnoringScrollEvents(); + scrollTop(window, 2000); + delay(() => history.push('/detail')); + }, + () => { + delay(() => history.goBack()); + }, + () => { + expect(scrollTop(window)).to.equal(2000); + done(); + }, + ]); + }); + it('should allow custom position', done => { const history = withRoutes( withScroll(createHistory(), () => [10, 20]), @@ -250,6 +278,36 @@ describe('ScrollBehavior', () => { }, ]); }); + + it('should ignore scroll events when startIgnoringScrollEvents is used', done => { + const history = withScrollElement( + withRoutes(withScroll(createHistory())), + ); + + unlisten = run(history, [ + () => { + history.startIgnoringScrollEvents(); + scrollTop(history.container, 5432); + delay(() => history.push('/detail')); + }, + () => { + delay(() => history.goBack()); + }, + () => { + expect(scrollTop(history.container)).to.equal(0); + history.stopIgnoringScrollEvents(); + scrollTop(history.container, 2000); + delay(() => history.push('/detail')); + }, + () => { + delay(() => history.goBack()); + }, + () => { + expect(scrollTop(history.container)).to.equal(2000); + done(); + }, + ]); + }); }); }); }); diff --git a/test/withScroll.js b/test/withScroll.js index 214e583..ee30bcd 100644 --- a/test/withScroll.js +++ b/test/withScroll.js @@ -86,9 +86,19 @@ export default function withScroll(history, shouldUpdateScroll) { }; } + function startIgnoringScrollEvents() { + scrollBehavior.startIgnoringScrollEvents(); + } + + function stopIgnoringScrollEvents() { + scrollBehavior.stopIgnoringScrollEvents(); + } + return { ...history, listen, registerScrollElement, + startIgnoringScrollEvents, + stopIgnoringScrollEvents, }; } diff --git a/types/index.d.ts b/types/index.d.ts index 298ad9c..7bb569e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -56,5 +56,9 @@ declare module 'scroll-behavior' { element: HTMLElement, target: ScrollPosition | string, ) => void; + + startIgnoringScrollEvents(): void; + + stopIgnoringScrollEvents(): void; } }