Skip to content

Commit

Permalink
feat(scroll): scroll to the same location like regular links
Browse files Browse the repository at this point in the history
  • Loading branch information
posva committed May 5, 2020
1 parent dd55e7c commit 5f22d4f
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 29 deletions.
20 changes: 15 additions & 5 deletions e2e/specs/scroll-behavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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()
},
}
4 changes: 3 additions & 1 deletion src/history/html5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
Expand Down
50 changes: 27 additions & 23 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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()
}
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit 5f22d4f

Please sign in to comment.