barbajs / barba

Create badass, fluid and smooth transitions between your website’s pages
https://barba.js.org/
MIT License
11.64k stars 474 forks source link

Problem with JS lifecycle after page transition #508

Closed strandofgenius closed 4 years ago

strandofgenius commented 4 years ago

I've installed v2.9.7 to hopefully integrate with a site using Craft CMS and VueJS for some components. I've tried to look into other tickets that brought up the issue of getting the main.js to re-init after a page transition but they reference older docs. I've attempted this both within a Vue instance as well as using vanilla js.

I referenced the legacy setup as well as the newer examples.

So far the only way I've gotten it to work is if I wrap my js in a function like initJS and call it in both of the methods afterEnter and after. I feel like this is super redundant and there has got to be a proper way to do this with either vanilla js or vue. Any help would be great.

Below is just a basic idea of how I managed to get it "functioning".


HTML STRUCTURE
<div data-barba="wrapper">
    <div data-barba="container" data-namespace="dynamicTitleName">
        [content goes here]
    </div>
    <script src="app.js"></script>
</div>

JS FILE

document.addEventListener('DOMContentLoaded', () => {
    const initJs = () => {
        document.getElementsByTagName('body')[0].classList.remove('open');
        document.getElementById('navToggle').addEventListener('click', () => {
            // per click add/remove open class to body tag
            document.getElementsByTagName('body')[0].classList.toggle('open');
            // pre click add/remove hidden class to fixed overlay main navigation
            document.getElementById('navOverlay').classList.toggle('hidden');
        });
    }

    barba.hooks.before(() => {
        barba.wrapper.classList.add('is-animating');
    });
    barba.hooks.afterEnter(() => {
        initJs();
    });
    barba.hooks.after(() => {
        barba.wrapper.classList.remove('is-animating');
        initJs();
    });

    barba.init({
        debug: true,
        transitions: [{
            name: 'legacy-example',
            leave: function(data) {
                var done = this.async();
                TweenMax.to(data.current.container, .25, {
                    opacity: 0,
                    onComplete: done
                });
            },
            enter: function(data) {
                var done = this.async();
                TweenMax.from(data.next.container, .25, {
                    opacity: 0,
                    onComplete: done
                });
            }
        }]
    });
});`
xavierfoucrier commented 4 years ago

Hi @strandofgenius,

When using VueJS, barba is not necessary, because Vue has built-in SPA stuff.

If you want to init some code "at browser startup" or "first load", you should use the once hook because it will run only "once".

If you want to re-init some code "after a transition has complete", you should use the after hook, or similar hooks like enter, beforeEnter, afterEnter.

In both cases, see the documentation about hooks here: https://barba.js.org/docs/userguide/syntax/#Hooks

Finally, if you just want to add classes to your body that reference transition states, take a look at the @barba/css plugin: https://barba.js.org/docs/plugins/css/

Hope this help :wink:

xavierfoucrier commented 4 years ago

@strandofgenius any feedback? Thanks!

strandofgenius commented 4 years ago

@xavierfoucrier I couldn't get the hooks to work for me. This did not fire for me when I initially loaded the page.

barba.hooks.once(()=> {
   initJs();
});

Instead, I used the following to handle classes and re-initing the js


    initJs();

    barba.init({
        debug: true,
        transitions: [{
            before: () => {
                console.log('add class is animating');
            },
            leave: (data) => {
                console.log('content leave transition');
                return new Promise(resolve => {
                    TweenMax.to(data.current.container, .25, {
                        opacity: 0,
                        onComplete: () => {
                            resolve();
                        }
                    });
                });
            },
            enter: (data) => {
                console.log('content enter transition');
                return new Promise(resolve => {
                    TweenMax.from(data.next.container, .25, {
                        opacity: 0,
                        onComplete: () => {
                            resolve();
                        }
                    });
                });
            },
            after: () => {
                console.log('remove class is animating');
                return new Promise(resolve => {
                    initJs();
                    resolve();
                });
            },
        }]
    });
xavierfoucrier commented 4 years ago

Hi @strandofgenius,

As specified in the documentation, you can't use a global once hook. I was talking about once hook inside a transition.

Can we close the issue? :smiley:

strandofgenius commented 4 years ago

Okay, that makes sense. Yes we can close it out.