Animated page transitions
See original GitHub issueAre you requesting a feature, reporting a bug or asking a question?
Feature
I’m working on animating page transitions but am running into some issues that make the solution quite hacky.
What is the current behavior?
The event to detect a page change even is onCurrentPageChanging
. After that returns the element is immediately removed from the DOM, meaning any animations won’t show.
What I do now when the event triggers is:
- Add a CSS class to trigger the animation.
- Prevent the page change (
options.allowChange
) - Call
survey.nextPage()
after a delay - Allow the page to change if the container already has the css class.
For the entrance transition, I store the direction we’re moving in (important to make sure a slide-in occurs from the correct window side) and use that to add a CSS class in the onAfterRenderPage
event.
What is the expected behavior?
Ideally the library would support animations a bit better by allowing us to control when elements get removed from the DOM.
Create a callback that can be used to hide the page container for example like this:
survey.hidePage = (htmlElement, cb) => {
// This code should hide the page, when it is done it should call `cb()` to notify SurveyJS that it may remove the element from the DOM.
// No animation:
cb();
// CSS Animation:
htmlElement.classList.add('fade-out-cool');
setTimeout(cb, 1000);
};
Fade-ins are inherently easier because we already have an event for elements that are added to the DOM.
Added benefit of my sample above is that it allows for some asynchronous behavior that can make the library appear smoother.
- Before removing the page we start the CSS animation.
- While the animation runs library code can already do the calculations required and therefore immediately load the next page when
cb()
is called.
While my example uses callbacks, ofcourse anno ~ 2021 it probably makes more sense to use promises.
For example, hidePage
could return a promise and when it resolves you remove the element:
survey.hidePage = (element) => {
element.classList.add('fade-out-cool');
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
};
// Imaginary code:
...
async nextPageInternal() => {
if (!currentPage.validate()) {
return currentPage.highlightErrors();
}
// This is the existing event
trigger(beforeChanging);
if (!changeAllowed) {
// Exit early
return;
}
let element = getDOMElementForPage(currentPage);
let hidePage = survey.hidePage(element);
let nextPage = calculateNextPage();
let renderedElement = renderPage(nextPage);
await hidePage;
// Try to do heavy lifting before awaiting the promise
activateAndInsertIntoDOM(nextPage, renderedElement);
}
Issue Analytics
- State:
- Created 3 years ago
- Comments:11 (6 by maintainers)
Top GitHub Comments
Thx for your comment @SamMousa. I’m doing the same thing, even with the same library ( good old animate.css 🙂 ) But nextPage() triggers couple of times. I’m using React, maybe that is effecting. That means I’m missing something. Okay, I’ll look into it, thx. 👍
Bump?