barbajs / barba

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

Set window.scroll, to position of link clicked #159

Closed Mellis84 closed 5 years ago

Mellis84 commented 7 years ago

Hey hey,

Just have to say I am loving this plugin man. I have an issue though which I hope you can help with, I have a list of projects on a page and when the link inside that project is clicked, the window scrolls to the projects position on the page, then performs the transitions and loads more content for that specific project. What I would like to know is how do I get the window scroll position back to where I initially clicked on the project after the transitions have finished when clicking back out of the project?

I have attached a screenshot and my code, hope you can help! it's been driving me crazy :)

screen shot 2017-07-07 at 13 40 18

`// set up barba document.addEventListener("DOMContentLoaded", function() {

// assign some variables
var lastElementClicked;
var isAnimating = false;

// options
Barba.Pjax.Dom.wrapperId = 'content-wrapper';
Barba.Pjax.Dom.containerClass = 'content-container';

Barba.Pjax.init();
Barba.Prefetch.init();

// listen to the event on click
// can now reference lastElementClicked to scroll to where it's been clicked
Barba.Dispatcher.on('linkClicked', function(el) {
    lastElementClicked = el;
});

var revealProject = Barba.BaseTransition.extend({
    start: function() {
        isAnimating = true;

        // set up functions asynchronously
        Promise
            .all([this.newContainerLoading, this.scrollToProject()])
            .then(this.showNewPage.bind(this));
    },

    // first transition function
    scrollToProject: function() {
        var _this = this;
        var project = lastElementClicked.closest(".project");
        var deferred = Barba.Utils.deferred();

        TweenLite.to(window, 0.5, {
            scrollTo: {
                y: project
            },
            onComplete: function() {
                deferred.resolve();
            }
        });

        return deferred.promise;
    },

    // transition to new page / object
    showNewPage: function() {

        // assign objects that are transitioning
        var _this = this;
        var newImage = _this.newContainer.querySelector('img');
        var newText = _this.newContainer.querySelector('summary');

        // reset and create a new timeline
        var tl = new TimelineMax({
            onComplete: function() {
                _this.newContainer.style.position = 'static';
                _this.done();

                // once timeline is finished, reset window to top
                // to avoid jumping
                window.scroll(0, 0);

                isAnimating = false;
            }
        });

        // preset transitional objects
        TweenLite.set(this.newContainer, {
            position: 'fixed',
            visibility: 'visible',
            top: 0,
            right: 0,
            bottom: 0,
            left: 0,
            opacity: 0,
            zIndex: 200
        });

        // start transitions
        tl.to(this.newContainer, 0.3, {
            opacity: 1 
        });

        tl.to(newImage, 0.3, { 
            opacity: 0 
        });

        tl.to(newText, 0.3, { 
            x: -200 
        });

    }
});

var closeProject = Barba.BaseTransition.extend({
    start: function() {
        isAnimating = true;

        Promise
            // Promise Async, do this, then this before load --- our animation 
            // functions in the .all will run first
            .all([this.newContainerLoading, this.scrollTop()])
            .then(this.hideNewPage.bind(this));

    },

    scrollTop: function() {
        var deferred = Barba.Utils.deferred();
        var obj = { y: window.pageYOffset };

        TweenLite.to(obj, 0.4, {
            y: 0,
            onUpdate: function() {
            if (obj.y === 0) {
                deferred.resolve();
            }

                window.scroll(0, obj.y);
            },
            onComplete: function() {
                deferred.resolve();
            }
        });

        return deferred.promise;
    },

    // transition out new page / object
    hideNewPage: function() {

        // assign objects that are transitioning
        var _this = this;
        var oldText = this.oldContainer.querySelector('summary');

        // reset and create a new timeline
        var tl = new TimelineMax({
            onComplete: function() {
                _this.newContainer.style.position = 'static';
                _this.done();
                isAnimating = false;
            }
        });

        // preset transitional objects
        TweenLite.set(this.newContainer, {
            position: 'fixed',
            visibility: 'visible',
            top: 0,
            right: 0,
            bottom: 0,
            left: 0,
            opacity: 0,
            zIndex: 200
        });

        // start transitions
        tl.to(oldText, 0.3, { 
            x: 0 
        });

        tl.to(this.newContainer, 0.3, { 
            opacity: 1 
        });

    }
});

Barba.Pjax.getTransition = function() {
    var transitionPage = revealProject;

    // if a page has a namespace of 'detail' use the following transition
    if (Barba.HistoryManager.prevStatus().namespace === 'detail') {
        transitionPage = closeProject;
    }

    return transitionPage;
};

});`

StudioZAAK commented 7 years ago

work with views an then use onLeaveCompleted within your detail view to restore the scroll position.

setup base page with anchor(s)

<div class="barba-container">
   <div id="achor"></div>
</div>

setup detail view(s) with data-namespace attribute

<div class="barba-container" data-namespace="detail_view">
   .. some stuff
</div>

add a detail view


var detail_view = Barba.BaseView.extend({
    namespace: 'detail_view',
    onLeaveCompleted: function() {
        console.log("detail_view has been removed from DOM");
        $('html, body').animate({
          scrollTop: $("#anchor").offset().top
        }, 10);
    }
  });

  // Don't forget to init the view!
  detail_view.init();
Mellis84 commented 7 years ago

Thanks for the fast response dude, I have a transition using the namespace 'detail' on the detail pages. I haven't tried on leave complete though... I can get to the anchor (projects) position when exiting if I specify an element directly... but not sure how to make it more dynamic, like whatever project has exited, the window has the scroll position set to that project.

I guess it would kind of be the reverse of what i have here? I had to target the parent of the lastElementClicked ('.project') for the window to scroll to.


Barba.Dispatcher.on('linkClicked', function(el) {
    lastElementClicked = el;
});
// first transition function
    scrollToProject: function() {
        var _this = this;
        var project = lastElementClicked.closest(".project");
        var deferred = Barba.Utils.deferred();

        TweenLite.to(window, 0.5, {
            scrollTo: {
                y: project
            },
            onComplete: function() {
                deferred.resolve();
            }
        });

        return deferred.promise;
    },`

Sorry if i'm really confusing.
Mellis84 commented 7 years ago

Worked it out! finally.

Had to use localStorage to store the scroll position once the transition has finished scrolling to the project:

First, when the scrollToProject function has completed, store the scroll position

        scrollToProject: function() {
            var project = $(lastElementClicked).parents('.project');
            var deferred = Barba.Utils.deferred();
            console.log(project);
            TweenLite.to(window, 0.5, {
                scrollTo: {
                    y: project
                },
                onComplete: function() {
                    deferred.resolve();
                    if(typeof(Storage) !== 'undefined') {
                        // Set scroll position
                        var lastYPos = +localStorage.getItem('scrollYPos');
                        localStorage.setItem('scrollYPos', window.scrollY);
                    }
                }
            });

            return deferred.promise;
        }

Then apply that scroll position when leaving the detail page:

var detailView = Barba.BaseView.extend({
        namespace: 'detail',
        onLeaveCompleted: function() {
            $html.style.overflow = 'initial';     

            if(typeof(Storage) !== 'undefined') {
                // Apply set scroll position from the scrollToProject function
                var lastYPos = +localStorage.getItem('scrollYPos');
                if (lastYPos) {
                    window.scrollTo(0, lastYPos);
                }
            }
        }
    });