]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat(scroll): allow passing behavior option
authorEduardo San Martin Morote <posva13@gmail.com>
Wed, 27 May 2020 12:52:16 +0000 (14:52 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Wed, 27 May 2020 12:52:16 +0000 (14:52 +0200)
BREAKING CHANGE: `scrollBehavior` doesn't accept an object with `x` and `y`
coordinates anymore. Instead it accepts an object like
[`ScrollToOptions`](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions)
with `left` and `top` properties. You can now also pass the
[`behavior`](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions/behavior)
property to enable smooth scrolling in most browsers.

README.md
e2e/scroll-behavior/index.ts
playground/router.ts
src/history/html5.ts
src/router.ts
src/scrollBehavior.ts

index 765c25a4b01ba474019552c17fcdf40c7811c29e..0e0d2be0b2d93e80fca8f86fb35bb564f74fd4ca 100644 (file)
--- a/README.md
+++ b/README.md
@@ -50,6 +50,7 @@ Check the [playground](https://github.com/vuejs/vue-router-next/tree/master/play
     // resolve the request
   })
   ```
+- The object returned in `scrollBehavior` is now similar to [`ScrollToOptions`](https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions): `x` is renamed to `left` and `y` is renamed to `top`.
 
 ### Typings
 
index f98dbea8235ed39ad8606fa3dff5014c461f493d..280c701ea7b41049f331882a9d9e7084cfe58a70 100644 (file)
@@ -40,7 +40,7 @@ const scrollBehavior: ScrollBehavior = async function (
 
       // specify offset of the element
       if (to.hash === '#anchor2') {
-        position.offset = { y: 100 }
+        position.offset = { top: 100 }
       }
 
       if (document.querySelector(position.selector)) {
@@ -56,7 +56,7 @@ const scrollBehavior: ScrollBehavior = async function (
     if (to.matched.some(m => m.meta.scrollToTop)) {
       // coords will be used if no selector is provided,
       // or if the selector didn't match any element.
-      return { x: 0, y: 0 }
+      return { left: 0, top: 0 }
     }
 
     return false
index 2b030a548145457580c25805e136429cfedb5ec6..924dccb19bc8580664a98aed10126ac06f3978b1 100644 (file)
@@ -152,7 +152,7 @@ export const router = createRouter({
     } else {
       // TODO: check if parent in common that works with alias
       if (to.matched.every((record, i) => from.matched[i] !== record))
-        return { x: 0, y: 0 }
+        return { left: 0, top: 0 }
     }
     // leave scroll as it is by not returning anything
     // https://github.com/Microsoft/TypeScript/issues/18319
index 4276caaa0301fb53a804b681f02eda7c5048404b..863cca6018289cf0e6889273e2cf1ec4b34efc16 100644 (file)
@@ -12,7 +12,7 @@ import {
 } from './common'
 import {
   computeScrollPosition,
-  ScrollPositionCoordinates,
+  _ScrollPositionNormalized,
 } from '../scrollBehavior'
 import { warn } from '../warning'
 import { stripBase } from '../location'
@@ -27,7 +27,7 @@ interface StateEntry extends HistoryState {
   forward: HistoryLocationNormalized | null
   position: number
   replaced: boolean
-  scroll: Required<ScrollPositionCoordinates> | null | false
+  scroll: _ScrollPositionNormalized | null | false
 }
 
 /**
index 48f0a9c42fdfc880a80d0251a7924a95978f5788..41aede494188e789c12bd2559971fb6df0261521 100644 (file)
@@ -15,13 +15,13 @@ import {
 } from './types'
 import { RouterHistory, HistoryState } from './history/common'
 import {
-  ScrollPositionCoordinates,
   ScrollPosition,
   getSavedScrollPosition,
   getScrollKey,
   saveScrollPosition,
   computeScrollPosition,
   scrollToPosition,
+  _ScrollPositionNormalized,
 } from './scrollBehavior'
 import { createRouterMatcher, PathParserOptions } from './matcher'
 import {
@@ -59,7 +59,7 @@ export interface ScrollBehavior {
   (
     to: RouteLocationNormalized,
     from: RouteLocationNormalizedLoaded,
-    savedPosition: Required<ScrollPositionCoordinates> | null
+    savedPosition: _ScrollPositionNormalized | null
   ): Awaitable<ScrollPosition | false | void>
 }
 
@@ -773,7 +773,7 @@ export function createRouter(options: RouterOptions): Router {
   ): Promise<any> {
     if (!isBrowser || !scrollBehavior) return Promise.resolve()
 
-    let scrollPosition: Required<ScrollPositionCoordinates> | null =
+    let scrollPosition: _ScrollPositionNormalized | null =
       (!isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0))) ||
       ((isFirstNavigation || !isPush) &&
         (history.state as HistoryState) &&
index 322543a6abf7fb84b671764a845ddb29d79f62c2..8417480ca7dbd629e09348de73fc2e5a4cc5e56f 100644 (file)
@@ -1,15 +1,33 @@
-import { RouteLocationNormalized, RouteLocationNormalizedLoaded } from './types'
+import {
+  RouteLocationNormalized,
+  RouteLocationNormalizedLoaded,
+  _RouteLocationBase,
+} from './types'
 import { warn } from './warning'
 
+// we use types instead of interfaces to make it work with HistoryStateValue type
+
+/**
+ * Scroll position similar to
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/ScrollToOptions | `ScrollToOptions`}.
+ * Note that not all browsers support `behavior`.
+ */
 export type ScrollPositionCoordinates = {
-  /**
-   * x position. 0 if not provided
-   */
-  x?: number
-  /**
-   * y position. 0 if not provided
-   */
-  y?: number
+  behavior?: ScrollOptions['behavior']
+  left?: number
+  top?: number
+}
+
+/**
+ * Internal normalized version of {@link ScrollPositionCoordinates} that always
+ * has `left` and `top` coordinates.
+ *
+ * @internal
+ */
+export type _ScrollPositionNormalized = {
+  behavior?: ScrollOptions['behavior']
+  left: number
+  top: number
 }
 
 export interface ScrollPositionElement {
@@ -47,24 +65,25 @@ export interface ScrollBehaviorHandler<T> {
 function getElementPosition(
   el: Element,
   offset: ScrollPositionCoordinates
-): Required<ScrollPositionCoordinates> {
+): _ScrollPositionNormalized {
   const docRect = document.documentElement.getBoundingClientRect()
   const elRect = el.getBoundingClientRect()
 
   return {
-    x: elRect.left - docRect.left - (offset.x || 0),
-    y: elRect.top - docRect.top - (offset.y || 0),
+    behavior: offset.behavior,
+    left: elRect.left - docRect.left - (offset.left || 0),
+    top: elRect.top - docRect.top - (offset.top || 0),
   }
 }
 
 export const computeScrollPosition = () =>
   ({
-    x: window.pageXOffset,
-    y: window.pageYOffset,
-  } as Required<ScrollPositionCoordinates>)
+    left: window.pageXOffset,
+    top: window.pageYOffset,
+  } as _ScrollPositionNormalized)
 
 export function scrollToPosition(position: ScrollPosition): void {
-  let normalizedPosition: ScrollPositionCoordinates
+  let scrollToOptions: ScrollPositionCoordinates
 
   if ('selector' in position) {
     /**
@@ -105,12 +124,14 @@ export function scrollToPosition(position: ScrollPosition): void {
         warn(`Couldn't find element with selector "${position.selector}"`)
       return
     }
-    normalizedPosition = getElementPosition(el, position.offset || {})
+    scrollToOptions = getElementPosition(el, position.offset || {})
   } else {
-    normalizedPosition = position
+    scrollToOptions = position
   }
 
-  window.scrollTo(normalizedPosition.x || 0, normalizedPosition.y || 0)
+  if ('scrollBehavior' in document.documentElement.style)
+    window.scrollTo(scrollToOptions)
+  else window.scrollTo(scrollToOptions.left || 0, scrollToOptions.top || 0)
 }
 
 export function getScrollKey(path: string, delta: number): string {
@@ -118,14 +139,11 @@ export function getScrollKey(path: string, delta: number): string {
   return position + path
 }
 
-export const scrollPositions = new Map<
-  string,
-  Required<ScrollPositionCoordinates>
->()
+export const scrollPositions = new Map<string, _ScrollPositionNormalized>()
 
 export function saveScrollPosition(
   key: string,
-  scrollPosition: Required<ScrollPositionCoordinates>
+  scrollPosition: _ScrollPositionNormalized
 ) {
   scrollPositions.set(key, scrollPosition)
 }