Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Navigation without history API should preserve scroll positions #1967

Closed
ahus1 opened this issue Jan 7, 2018 · 3 comments
Closed

Navigation without history API should preserve scroll positions #1967

ahus1 opened this issue Jan 7, 2018 · 3 comments

Comments

@ahus1
Copy link

ahus1 commented Jan 7, 2018

What problem does this feature solve?

Using vue router without history API makes it easier for a backend to serve just an index.html as only hashes are added to the URL for the different routes. This is the reason we haven't switched to html5 history mode.

But using the hashes navigation doesn't preserve the scroll position. It doesn't even call the scrollBehavior methods that would make an implementation easier.

A working solution for us (and probably most other other users) would be to save the scroll position once-per-route in pure javascript and provide these values once you enter the route again.

I open this issue because I think this will help others. If you consider it out of scope for vue-router, consider closing it right away.

What does the proposed API look like?

No additional API would be provided. ScrollBehavior would be called even if not in HTML5 mode. Scroll positions would be saved in a once-per-route in pure JavaScript inside vue-router.

For us the following code works for forward and backward javascript navigation. It's part of the following open source app - https://latest.dukecon.org/pwa/javaland/2018/ (full source available here https://github.com/dukecon/dukecon_pwa/blob/develop/src/main.js)

  // for each page, store the scroll position
  var positionStore = {}

  /* record the scrolling on current route (works better as back-navigation scrolls to different position,
  and this would otherwise be recorded by beforeEach() */
  window.onscroll = function () {
    positionStore[app.$route.path] = {
      x: window.pageXOffset,
      y: window.pageYOffset
    }
  }

  // whenever the route changes, scroll to old position
  router.beforeEach((to, from, next) => {
    const oldPosition = positionStore[to.path]
    // restore position after next screen rendering
    app.$nextTick(() => {
      if (!oldPosition || (oldPosition.y === 0 && oldPosition.x === 0)) {
        window.scrollTo(0, 0)
      } else {
        // I found that rendering of the screen might take a little bit more time,
        // therefore wait a bit if we don't scroll to the top
        window.setTimeout(function () {
          window.scrollTo(oldPosition.x, oldPosition.y)
        }, 50)
      }
    })
    next()
  })
@posva
Copy link
Member

posva commented Jan 7, 2018

Using vue router without history API makes it easier for a backend to serve just an index.html as only hashes are added to the URL for the different routes. This is the reason we haven't switched to html5 history mode.

Are you aware of this page about configuring servers to always serve the index.html page?

But using the hashes navigation doesn't preserve the scroll position. It doesn't even call the scrollBehavior methods that would make an implementation easier.

scrollBehavior actually works with hash mode since #1662, if it's not, could you provide a repro please?

@ahus1
Copy link
Author

ahus1 commented Jan 7, 2018

I wasn't aware of the change in 2.8.0 - sorry to bother you.

@ahus1 ahus1 closed this as completed Jan 7, 2018
@posva
Copy link
Member

posva commented Jan 7, 2018

No worries! It could have been a regression

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants