locomotivemtl / locomotive-scroll

🛤 Detection of elements in viewport & smooth scrolling with parallax.
https://locomotivemtl.github.io/locomotive-scroll
MIT License
7.93k stars 1.11k forks source link

Updating Scroll height on page change #31

Closed carlfmichel closed 5 years ago

carlfmichel commented 5 years ago

We are using Locomotive Scroll (LS) on a site that utilizes a page transition plugin. When we transition to a new page sometime LS doesn't allow the user to scroll all the way down. I'm guessing this has something to do with the page not fully loaded when LS is initialized. From what I can tell, the Locomotive site is similar. How do you all get around this obstacle. Any insights would be highly appreciated!

patchampoux commented 5 years ago

I had the same problem using Barba.js. You need to destroy the instance of the plugin using scroll.destroy(); and initialize it every time a page is loaded.

regenrek commented 5 years ago

Hi,

I don't know if it helps you since its vuejs related but I've written a mixin which calls update() and destroy() method on $route() change. Could be simple to adapt for vanilla and react I guess...

Relevant Parts are in mixins/locomotive.js

export default {
  watch: {
    $route() {
      console.log("route changed: ", this.$route);
      this.lmS.update();
    }
  },
  mounted() {
    this.$nextTick(
      function() {
        this.lmS = new this.locomotiveScroll({
          el: document.querySelector("#js-scroll"),
          smooth: true /* if false disable overflow: hidden on html, body */
        });
      }.bind(this)
    );
  },
  destroyed() {
    this.lmS.destroy();
  },
};

Here is a Sandbox Demo, which handles also scroll and resize events https://codesandbox.io/embed/locomotive-scroll-nuxt-jtoyb

Jerek0 commented 5 years ago

On our projects each page has its own instance of LS. We destroy the LS instance of the page we are leaving, and we instantiate a new one on the page we are entering.

You can also use the update method to refresh LS measurements when a layout modification occurs (i.e. an image finished loading, or content is added).

jaro-io commented 4 years ago

hey @patchampoux and @Jerek0 , how exactly did you do that? can you show us the code? i am struggling too using barba.js.. thank you so much

patchampoux commented 4 years ago

main.js.zip

@jarovision The lines you want to look at are 21 to 28 and 651. This is using barba v2.

Hope it helps.

elebumm commented 4 years ago

I had this issue with a React application (specifically Gatsby). In my class-based component I just had it like:

componentDidMount() {
    this.scroll = new LocomotiveScroll({
       el: document.querySelector("body"),
       smooth: true,
    })
)

componentWillUnmount() {
    this.scroll.destroy()
}
jaro-io commented 4 years ago

Thank you so much. I managed now. Have a good life. :)

On 12. Feb 2020, at 23:56, Lewis Menelaws notifications@github.com wrote:

 I had this issue with a React (specifically Gatsby). In my class-based component I just had it like:

componentDidMount() { this.scroll = new LocomotiveScroll({ el: document.querySelector("body"), smooth: true, }) )

componentWillUnmount() { this.scroll.destroy() } — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

Mulegoat commented 4 years ago

Hi there,

Before opening a new issue I was wondering how you guys handle updating the scroll instance when using components like accordions or animations that affect the height of the scroll container? I know this question is in reference to routing but attaching scroll.update to click events does not seem to do anything?

If anybody has an example that would be great.

Jerek0 commented 4 years ago

@Mulegoat: Calling update on click events is the way to go but make sure the layout changes are done before doing so (e.g. if your accordion is not fully opened yet, it won't work properly).

Also, please update LS to 3.3.5 or above as it fixes an important issue with update.

Mulegoat commented 4 years ago

Thank you @Jerek0 - I'm managing to successfully call update now. The container resizes when it's height changes perfectly 99% of the time, at first sticky items did not maintain their position - note to anyone else experiencing this - remove any top, bottom or position sticky css on data-sticky elements :).

Quick question, how do you normally go about writing functions that need to access LS? Do you place them all in global scope in the setTimeout function as per the demo? Lets say I had multiple different funcitons for ajaxing content, accordions etc, would you attach a single callback function that only calls scroll.update() to all these kinds of functions?

I have another question regarding Intersection Obserever but will open a new thread if I cannot figure it out for myself.

Many thanks again Jeremy, and congrats to everyone at Locomotive for the recent awards. Richly deserved!

Jerek0 commented 4 years ago

how do you normally go about writing functions that need to access LS? Do you place them all in global scope in the setTimeout function as per the demo? Lets say I had multiple different funcitons for ajaxing content, accordions etc, would you attach a single callback function that only calls scroll.update() to all these kinds of functions?

It's really up to you and how you like to work. You can store your LS instance globally to access it from anywhere, or you can setup a custom event listener linked to LS that you can call from anywhere as well.

At Locomotive we use modularorg/modularjs which has its own system for calling methods bewteen modules (e.g. this.call('update', args, 'Scroll') ). Also, we usually store main scroll state globally in order to be able to get some data like current scroll value, limit, direction, speed, etc.

E.g.

this.scroll.on('scroll', (args) => {
    window.yournamespace.scroll.state = args
})

Thanks for the kind words 🙏 The whole team is really proud of this achievement and we'll continue to do our best to deliver high quality work!

JonQuayle commented 4 years ago

Sorry to open this one up again but I am working through this browser resize issue I am having - sounds exactly like this issue. I'm still a bit of a javascript newbie though... I understand that the LS scroll instance has to be updated, but how do I run this when the browser window is resized? On a side note - for people who are not quite up to date with javascript and still learning, it would be helpful to have a bit more of this sort of 'quick start' or 'this is how you do this' info on the plugin page. Thanks for making this available though, its awesome. Any help is appreciated!


edit by @jerek0 : follow up on https://github.com/locomotivemtl/locomotive-scroll/issues/112#event-3249140797

onseyi commented 4 years ago

HI there, I try to do the below on my code but did not work pls help on the code.

const locoScroll = new locomotiveScroll({
        el: document.querySelector('.o-scroll'),
        smooth: true
});

barba.init({
    sync: true,
    transitions: [{
        async leave(data) {
            const done = this.async();

            pageTransition();
            // await delay(1500);
            done();
        },

        async enter(data) {
          contentAnimation();
        },

        async once(data) {
          contentAnimation();
        },

        async beforeEnter(data) {
            locoScroll.destroy();
          }     
    }]
});
patchampoux commented 4 years ago

HI there, I try to do the below on my code but did not work pls help on the code.

const locoScroll = new locomotiveScroll({
      el: document.querySelector('.o-scroll'),
      smooth: true
});

barba.init({
    sync: true,
    transitions: [{
        async leave(data) {
            const done = this.async();

            pageTransition();
            // await delay(1500);
            done();
        },

        async enter(data) {
          contentAnimation();
        },

        async once(data) {
        contentAnimation();
      },

        async beforeEnter(data) {
          locoScroll.destroy();
        }     
    }]
});

You can look at this page, it is well documented : https://barba.js.org/docs/advanced/third-party/#Locomotive-scroll

Mulegoat commented 4 years ago

main.js.zip

@jarovision The lines you want to look at are 21 to 28 and 651. This is using barba v2.

Hope it helps.

Hi @patchampoux

Are you sure this version is using Barba v2? I can't seem to get it working with v2, but v1 seems to work ok. Just curious if this is a typo or something I'm probably doing wrong :)

patchampoux commented 4 years ago

main.js.zip @jarovision The lines you want to look at are 21 to 28 and 651. This is using barba v2. Hope it helps.

Hi @patchampoux

Are you sure this version is using Barba v2? I can't seem to get it working with v2, but v1 seems to work ok. Just curious if this is a typo or something I'm probably doing wrong :)

Yes, this is a typo, sorry.

Paupy commented 3 years ago

Hey,

First, thank you for your library!

I have the same issue and even if i call "update" after the modularLoad ready event, my new page don't have the right height. I have to resize manually and that's ok. Do you have an idea ?

HunterHolthaus commented 3 years ago

I'm having this same issue using Swup for page transitions. Basically where the height of the transitioned page with locomotive initialized doesnt allow the user to scroll all the way down/content is cutoff. One note I've noticed if I refresh the page again the issue is fixed and I can scroll the whole thing. Anyone know how to get this working with Swup specifically, is it similar to the barba instructions here: https://barba.js.org/docs/advanced/third-party/#Locomotive-scroll ?

Mostly looking for some more specific code for this - like how to destroy the LS instance of the page we are leaving and instantiating a new one on the page we are entering. And where that should live in my function? Obviously a noob at this btw but your time and thoughts are much appreciated!
https://user-images.githubusercontent.com/49177233/133552545-db8b2d3b-e1c8-41bf-b4c6-0bc341f40ed9.mov

//Swup stuff
const swup = new Swup({
plugins: [new SwupHeadPlugin()]
});

const options = {
cache: true,
};

//Destroying a plugin on my homepage so it doesnt mess with the next one
document.addEventListener('swup:willReplaceContent', (event) => {
fullpage_api.destroy('all');
});

//Reloading JS on new project page
init();
swup.on('contentReplaced', init);

function init() {
if (document.querySelector('.js-reload')) { //This checks if this element is on the the page (in the html)
new blah(); // If it is then it creates a new instance of the function
}
}

var blahStart = new blah(); // This initialises the below function the first time (first page load not controlled by swup)

function blah() { // This it the wrapper funtion

// This is my locomotve script
const scroller = new LocomotiveScroll({
el: document.querySelector('[data-scroll-container]'),
smooth: true
});

};
chaiperez commented 2 years ago

@HunterHolthaus I was able to resolve this doing the following:

const swup = new Swup({ plugins: [ new SwupPreloadPlugin(), new SwupBodyClassPlugin(), new SwupHeadPlugin() ], });

function init() { let scrollContainer = document.querySelector('[data-scroll-container]'); scroll = new LocomotiveScroll({ el: scrollContainer, smooth: true });

setTimeout(() => { scroll.update(); }, 500); }

let scroll;

function unload(){ scroll.destroy(); }

swup.on("contentReplaced", init); swup.on("willReplaceContent", unload);

init();