diff --git a/docs/en/advanced/scroll-behavior.md b/docs/en/advanced/scroll-behavior.md index 99d468991..a9281ac40 100644 --- a/docs/en/advanced/scroll-behavior.md +++ b/docs/en/advanced/scroll-behavior.md @@ -2,7 +2,7 @@ When using client-side routing, we may want to scroll to top when navigating to a new route, or preserve the scrolling position of history entries just like real page reload does. `vue-router` allows you to achieve these and even better, allows you to completely customize the scroll behavior on route navigation. -**Note: this feature only works in HTML5 history mode.** +**Note: this feature only works if the browser supports `history.pushState`.** When creating the router instance, you can provide the `scrollBehavior` function: @@ -60,3 +60,21 @@ scrollBehavior (to, from, savedPosition) { ``` We can also use [route meta fields](meta.md) to implement fine-grained scroll behavior control. Check out a full example [here](https://github.com/vuejs/vue-router/blob/dev/examples/scroll-behavior/app.js). + +### Async Scrolling + +> New in 2.8.0 + +You can also return a Promise that resolves to the desired position descriptor: + +``` js +scrollBehavior (to, from, savedPosition) { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve({ x: 0, y: 0 }) + }, 500) + }) +} +``` + +It's possible to hook this up with events from a page-level transition component to make the scroll behavior play nicely with your page transitions, but due to the possible variance and complexity in use cases, we simply provide this primitive to enable specific userland implementations. diff --git a/docs/en/api/options.md b/docs/en/api/options.md index 020feeec8..2a65792d5 100644 --- a/docs/en/api/options.md +++ b/docs/en/api/options.md @@ -74,11 +74,16 @@ Signature: ``` - ( + type PositionDescriptor = + { x: number, y: number } | + { selector: string } | + ?{} + + type scrollBehaviorHandler = ( to: Route, from: Route, savedPosition?: { x: number, y: number } - ) => { x: number, y: number } | { selector: string } | ?{} + ) => PositionDescriptor | Promise ``` For more details see [Scroll Behavior](../advanced/scroll-behavior.md). diff --git a/flow/declarations.js b/flow/declarations.js index 0efebfa96..6f7b77f3b 100644 --- a/flow/declarations.js +++ b/flow/declarations.js @@ -28,6 +28,7 @@ declare type NavigationGuard = ( declare type AfterNavigationHook = (to: Route, from: Route) => any type Position = { x: number, y: number }; +type PositionResult = Position | { selector: string, offset?: Position } | void; declare type RouterOptions = { routes?: Array; @@ -41,7 +42,7 @@ declare type RouterOptions = { to: Route, from: Route, savedPosition: ?Position - ) => Position | { selector: string, offset?: Position } | ?{}; + ) => PositionResult | Promise; } declare type RedirectOption = RawLocation | ((to: Route) => RawLocation) diff --git a/src/util/scroll.js b/src/util/scroll.js index f2fcd8687..9991adaa7 100644 --- a/src/util/scroll.js +++ b/src/util/scroll.js @@ -47,7 +47,11 @@ export function handleScroll ( if (typeof shouldScroll.then === 'function') { shouldScroll.then(shouldScroll => { - scrollToPosition(shouldScroll, position) + scrollToPosition((shouldScroll: any), position) + }).catch(err => { + if (process.env.NODE_ENV !== 'production') { + assert(false, err.toString()) + } }) } else { scrollToPosition(shouldScroll, position) diff --git a/types/router.d.ts b/types/router.d.ts index bed016ee0..1ad77b4ef 100644 --- a/types/router.d.ts +++ b/types/router.d.ts @@ -45,6 +45,7 @@ declare class VueRouter { } type Position = { x: number, y: number }; +type PositionResult = Position | { selector: string, offset?: Position } | void; export interface RouterOptions { routes?: RouteConfig[]; @@ -59,7 +60,7 @@ export interface RouterOptions { to: Route, from: Route, savedPosition: Position | void - ) => Position | { selector: string, offset?: Position } | void; + ) => PositionResult | Promise; } type RoutePropsFunction = (route: Route) => Object; diff --git a/types/test/index.ts b/types/test/index.ts index fa76827f0..80db6aac8 100644 --- a/types/test/index.ts +++ b/types/test/index.ts @@ -60,6 +60,11 @@ const router = new VueRouter({ if (savedPosition) { return savedPosition; } + + return Promise.resolve({ + x: 0, + y: 0 + }) }, routes: [ { path: "/", name: "home", component: Home, children: [