diff --git a/lib/app/components/nuxt-child.js b/lib/app/components/nuxt-child.js index 6181d709df..6276c66d85 100644 --- a/lib/app/components/nuxt-child.js +++ b/lib/app/components/nuxt-child.js @@ -29,6 +29,12 @@ export default { listeners[key] = transition[key].bind(_parent) } }) + // Add triggerScroll event on beforeEnter (fix #1376) + let beforeEnter = listeners.beforeEnter + listeners.beforeEnter = (el) => { + window.$nuxt.$emit('triggerScroll') + if (beforeEnter) return beforeEnter.call(_parent, el) + } let routerView = [ h('router-view', data) diff --git a/lib/app/router.js b/lib/app/router.js index efad4256db..47c0f653d9 100644 --- a/lib/app/router.js +++ b/lib/app/router.js @@ -26,27 +26,40 @@ uniqBy(_components, '_name').forEach((route) => { %>const <%= route._name %> = ( <% if (router.scrollBehavior) { %> const scrollBehavior = <%= serialize(router.scrollBehavior).replace('scrollBehavior(', 'function(').replace('function function', 'function') %> <% } else { %> -const scrollBehavior = (to, from, savedPosition) => { - // SavedPosition is only available for popstate navigations. - if (savedPosition) { - return savedPosition - } else { - let position = {} - // If no children detected - if (to.matched.length < 2) { - // Scroll to the top of the page - position = { x: 0, y: 0 } - } - else if (to.matched.some((r) => r.components.default.options.scrollToTop)) { - // If one of the children has scrollToTop option set to true - position = { x: 0, y: 0 } - } - // If link has anchor, scroll to anchor by returning the selector - if (to.hash) { - position = { selector: to.hash } - } - return position +if (process.client) { + window.history.scrollRestoration = 'manual' +} +const scrollBehavior = function (to, from, savedPosition) { + // if the returned position is falsy or an empty object, + // will retain current scroll position. + let position = false + + // if no children detected + if (to.matched.length < 2) { + // scroll to the top of the page + position = { x: 0, y: 0 } + } else if (to.matched.some((r) => r.components.default.options.scrollToTop)) { + // if one of the children has scrollToTop option set to true + position = { x: 0, y: 0 } } + + // savedPosition is only available for popstate navigations (back button) + if (savedPosition) { + position = savedPosition + } + + return new Promise(resolve => { + // wait for the out transition to complete (if necessary) + window.$nuxt.$once('triggerScroll', () => { + // coords will be used if no selector is provided, + // or if the selector didn't match any element. + if (to.hash && document.querySelector(to.hash)) { + // scroll to anchor by returning the selector + position = { selector: to.hash } + } + resolve(position) + }) + }) } <% } %>