Skip to content

Commit

Permalink
feat: add API to pause scroll position saving (#306)
Browse files Browse the repository at this point in the history
* fix: don't save the scroll position between transitionHook and updateScroll

* fixes

* refactor: use explicit API for ignoring scroll events

* tests: add test for ignoring scroll events

* fix: ignore scroll events for custom elements + tests
  • Loading branch information
hedgepigdaniel authored and taion committed Dec 18, 2019
1 parent 229b9e2 commit c57872a
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 4 deletions.
24 changes: 20 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default class ScrollBehavior {
this._checkWindowScrollHandle = null;
this._windowScrollTarget = null;
this._numWindowScrollAttempts = 0;
this._ignoreScrollEvents = false;

this._scrollElements = {};

Expand All @@ -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);
}
});
});
}
Expand All @@ -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,
);
Expand All @@ -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,
);
Expand Down Expand Up @@ -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
Expand Down
58 changes: 58 additions & 0 deletions test/ScrollBehavior.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]),
Expand Down Expand Up @@ -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();
},
]);
});
});
});
});
Expand Down
10 changes: 10 additions & 0 deletions test/withScroll.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,19 @@ export default function withScroll(history, shouldUpdateScroll) {
};
}

function startIgnoringScrollEvents() {
scrollBehavior.startIgnoringScrollEvents();
}

function stopIgnoringScrollEvents() {
scrollBehavior.stopIgnoringScrollEvents();
}

return {
...history,
listen,
registerScrollElement,
startIgnoringScrollEvents,
stopIgnoringScrollEvents,
};
}
4 changes: 4 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,9 @@ declare module 'scroll-behavior' {
element: HTMLElement,
target: ScrollPosition | string,
) => void;

startIgnoringScrollEvents(): void;

stopIgnoringScrollEvents(): void;
}
}

0 comments on commit c57872a

Please sign in to comment.