Skip to content

Navigation without history API should preserve scroll positions #1967

@ahus1

Description

@ahus1

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()
  })

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions