router.scrollBehavior.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import { getMatchedComponents } from './utils'
  2. if (process.client) {
  3. if ('scrollRestoration' in window.history) {
  4. window.history.scrollRestoration = 'manual'
  5. // reset scrollRestoration to auto when leaving page, allowing page reload
  6. // and back-navigation from other pages to use the browser to restore the
  7. // scrolling position.
  8. window.addEventListener('beforeunload', () => {
  9. window.history.scrollRestoration = 'auto'
  10. })
  11. // Setting scrollRestoration to manual again when returning to this page.
  12. window.addEventListener('load', () => {
  13. window.history.scrollRestoration = 'manual'
  14. })
  15. }
  16. }
  17. export default function (to, from, savedPosition) {
  18. // If the returned position is falsy or an empty object, will retain current scroll position
  19. let position = false
  20. const Pages = getMatchedComponents(to)
  21. // Scroll to the top of the page if...
  22. if (
  23. // One of the children set `scrollToTop`
  24. Pages.some(Page => Page.options.scrollToTop) ||
  25. // scrollToTop set in only page without children
  26. (Pages.length < 2 && Pages.every(Page => Page.options.scrollToTop !== false))
  27. ) {
  28. position = { x: 0, y: 0 }
  29. }
  30. // savedPosition is only available for popstate navigations (back button)
  31. if (savedPosition) {
  32. position = savedPosition
  33. }
  34. const nuxt = window.$nuxt
  35. if (
  36. // Route hash changes
  37. (to.path === from.path && to.hash !== from.hash) ||
  38. // Initial load (vuejs/vue-router#3199)
  39. to === from
  40. ) {
  41. nuxt.$nextTick(() => nuxt.$emit('triggerScroll'))
  42. }
  43. return new Promise((resolve) => {
  44. // wait for the out transition to complete (if necessary)
  45. nuxt.$once('triggerScroll', () => {
  46. // coords will be used if no selector is provided,
  47. // or if the selector didn't match any element.
  48. if (to.hash) {
  49. let hash = to.hash
  50. // CSS.escape() is not supported with IE and Edge.
  51. if (typeof window.CSS !== 'undefined' && typeof window.CSS.escape !== 'undefined') {
  52. hash = '#' + window.CSS.escape(hash.substr(1))
  53. }
  54. try {
  55. if (document.querySelector(hash)) {
  56. // scroll to anchor by returning the selector
  57. position = { selector: hash }
  58. }
  59. } catch (e) {
  60. console.warn('Failed to save scroll position. Please add CSS.escape() polyfill (https://github.com/mathiasbynens/CSS.escape).')
  61. }
  62. }
  63. resolve(position)
  64. })
  65. })
  66. }