]> git.ipfire.org Git - thirdparty/vuejs/router.git/commitdiff
feat(scroll): scroll to the same location like regular links
authorEduardo San Martin Morote <posva13@gmail.com>
Tue, 5 May 2020 09:42:56 +0000 (11:42 +0200)
committerEduardo San Martin Morote <posva13@gmail.com>
Tue, 5 May 2020 09:42:56 +0000 (11:42 +0200)
e2e/specs/scroll-behavior.js
src/history/html5.ts
src/router.ts

index 8fe376469f404632b755be2cb85535e327d957bf..4deab32905ec84e9d9a6830582600f9c69307bec 100644 (file)
@@ -122,11 +122,9 @@ module.exports = {
       .click('li:nth-child(4) a')
       .assert.evaluate(
         function () {
-          // TODO: change implementation to use `afterEach`
-          return true
-          // return (
-          //   document.getElementById('anchor').getBoundingClientRect().top < 1
-          // )
+          return (
+            document.getElementById('anchor').getBoundingClientRect().top < 1
+          )
         },
         null,
         'scroll to anchor when the route is the same'
@@ -199,6 +197,18 @@ module.exports = {
         'scroll to anchor'
       )
 
+      .url('http://localhost:8080/scroll-behavior/bar#anchor')
+      .waitForElementPresent('.view.bar', TIMEOUT)
+      .assert.evaluate(
+        function () {
+          return (
+            document.getElementById('anchor').getBoundingClientRect().top < 1
+          )
+        },
+        null,
+        'scroll to anchor when directly navigating to it'
+      )
+
       .end()
   },
 }
index 0e72ae0df3961489a2ecf00603814b6522b04fa8..7318928620cd5cf43344e4fec677bcc9d4e7821e 100644 (file)
@@ -187,7 +187,9 @@ function useHistoryStateNavigation(base: string) {
         // the length is off by one, we need to decrease it
         position: history.length - 1,
         replaced: true,
-        scroll: computeScrollPosition(),
+        // don't add a scroll as the user may have an anchor and we want
+        // scrollBehavior to be triggered without a saved position
+        scroll: null,
       },
       true
     )
index cb8da2ece6f8669bb60d514ec054adff2cf0c476..4393d41ba6580539bc2b0b320d5fbd9120ad5fac 100644 (file)
@@ -388,11 +388,23 @@ export function createRouter(options: RouterOptions): Router {
     toLocation.redirectedFrom = redirectedFrom
     let failure: NavigationFailure | void | undefined
 
-    if (!force && isSameRouteLocation(from, targetLocation))
+    if (!force && isSameRouteLocation(from, targetLocation)) {
       failure = createRouterError<NavigationFailure>(
         ErrorTypes.NAVIGATION_DUPLICATED,
         { to: toLocation, from }
       )
+      // trigger scroll to allow scrolling to the same anchor
+      handleScroll(
+        from,
+        from,
+        // this is a push, the only way for it to be triggered from a
+        // history.listen is with a redirect, which makes it become a pus
+        true,
+        // This cannot be the first navigation because the initial location
+        // cannot be manually navigated to
+        false
+      )
+    }
 
     return (failure ? Promise.resolve(failure) : navigate(toLocation, from))
       .catch((error: NavigationFailure | NavigationRedirectError) => {
@@ -609,23 +621,7 @@ export function createRouter(options: RouterOptions): Router {
 
     // accept current navigation
     currentRoute.value = toLocation
-    // TODO: call handleScroll in afterEach so it can also be triggered on
-    // duplicated navigation (e.g. same anchor navigation). It needs exposing
-    // the navigation information (type, direction)
-    if (isBrowser) {
-      // if we are pushing, we cannot have a saved position. This is important
-      // when visiting /b from /a, scrolling, going back to /a by with the back
-      // button and then clicking on a link to /b instead of the forward button
-      const savedScroll =
-        !isPush && getSavedScrollPosition(getScrollKey(toLocation.fullPath, 0))
-      handleScroll(
-        toLocation,
-        from,
-        savedScroll || ((isFirstNavigation || !isPush) && state && state.scroll)
-      ).catch(err => {
-        triggerError(err)
-      })
-    }
+    handleScroll(toLocation, from, isPush, isFirstNavigation)
 
     markAsReady()
   }
@@ -751,17 +747,25 @@ export function createRouter(options: RouterOptions): Router {
   }
 
   // Scroll behavior
-
   function handleScroll(
     to: RouteLocationNormalizedLoaded,
     from: RouteLocationNormalizedLoaded,
-    scrollPosition?: Required<ScrollPositionCoordinates>
-  ) {
-    if (!scrollBehavior) return Promise.resolve()
+    isPush: boolean,
+    isFirstNavigation: boolean
+  ): Promise<any> {
+    if (!isBrowser || !scrollBehavior) return Promise.resolve()
+
+    let scrollPosition: Required<ScrollPositionCoordinates> | null =
+      (!isPush && getSavedScrollPosition(getScrollKey(to.fullPath, 0))) ||
+      ((isFirstNavigation || !isPush) &&
+        (history.state as HistoryState) &&
+        history.state.scroll) ||
+      null
 
     return nextTick()
-      .then(() => scrollBehavior!(to, from, scrollPosition || null))
+      .then(() => scrollBehavior!(to, from, scrollPosition))
       .then(position => position && scrollToPosition(position))
+      .catch(triggerError)
   }
 
   function go(delta: number) {