router.scrollBehavior.js 2.4 KB

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