Skip to content

Commit 62d9c41

Browse files
committed
make scrollBehavior work with transitions by handling a promise
1 parent d2aa552 commit 62d9c41

File tree

3 files changed

+43
-20
lines changed

3 files changed

+43
-20
lines changed

examples/scroll-behavior/app.js

+12-3
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@ const Bar = {
2020
// - only available in html5 history mode
2121
// - defaults to no scroll behavior
2222
// - return false to prevent scroll
23-
const scrollBehavior = (to, from, savedPosition) => {
23+
const scrollBehavior = async function (to, from, savedPosition) {
2424
if (savedPosition) {
2525
// savedPosition is only available for popstate navigations.
2626
return savedPosition
2727
} else {
2828
const position = {}
29+
let delay = 500
2930
// new navigation.
3031
// scroll to anchor by returning the selector
3132
if (to.hash) {
@@ -35,14 +36,20 @@ const scrollBehavior = (to, from, savedPosition) => {
3536
if (to.hash === '#anchor2') {
3637
position.offset = { y: 100 }
3738
}
39+
40+
if (document.querySelector(to.hash)) {
41+
delay = 0
42+
}
3843
}
3944
// check if any matched route config has meta that requires scrolling to top
4045
if (to.matched.some(m => m.meta.scrollToTop)) {
41-
// cords will be used if no selector is provided,
46+
// coords will be used if no selector is provided,
4247
// or if the selector didn't match any element.
4348
position.x = 0
4449
position.y = 0
4550
}
51+
// wait for the out transition to complete (if necessary)
52+
await (new Promise(resolve => setTimeout(resolve, delay)))
4653
// if the returned position is falsy or an empty object,
4754
// will retain current scroll position.
4855
return position
@@ -72,7 +79,9 @@ new Vue({
7279
<li><router-link to="/bar#anchor">/bar#anchor</router-link></li>
7380
<li><router-link to="/bar#anchor2">/bar#anchor2</router-link></li>
7481
</ul>
75-
<router-view class="view"></router-view>
82+
<transition name="fade" mode="out-in">
83+
<router-view class="view"></router-view>
84+
</transition>
7685
</div>
7786
`
7887
}).$mount('#app')

examples/scroll-behavior/index.html

+6
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
<!DOCTYPE html>
22
<link rel="stylesheet" href="/global.css">
33
<style>
4+
.fade-enter-active, .fade-leave-active {
5+
transition: opacity .5s ease;
6+
}
7+
.fade-enter, .fade-leave-active {
8+
opacity: 0
9+
}
410
.view {
511
border: 1px solid red;
612
height: 2000px;

src/util/scroll.js

+25-17
Original file line numberDiff line numberDiff line change
@@ -36,28 +36,16 @@ export function handleScroll (
3636

3737
// wait until re-render finishes before scrolling
3838
router.app.$nextTick(() => {
39-
let position = getScrollPosition()
39+
const position = getScrollPosition()
4040
const shouldScroll = behavior(to, from, isPop ? position : null)
41+
4142
if (!shouldScroll) {
4243
return
4344
}
44-
const isObject = typeof shouldScroll === 'object'
45-
if (isObject && typeof shouldScroll.selector === 'string') {
46-
const el = document.querySelector(shouldScroll.selector)
47-
if (el) {
48-
let offset = shouldScroll.offset && typeof shouldScroll.offset === 'object' ? shouldScroll.offset : {}
49-
offset = normalizeOffset(offset)
50-
position = getElementPosition(el, offset)
51-
} else if (isValidPosition(shouldScroll)) {
52-
position = normalizePosition(shouldScroll)
53-
}
54-
} else if (isObject && isValidPosition(shouldScroll)) {
55-
position = normalizePosition(shouldScroll)
56-
}
5745

58-
if (position) {
59-
window.scrollTo(position.x, position.y)
60-
}
46+
Promise.resolve(shouldScroll).then((shouldScroll) => {
47+
scrollToPosition(shouldScroll, position)
48+
})
6149
})
6250
}
6351

@@ -109,3 +97,23 @@ function normalizeOffset (obj: Object): Object {
10997
function isNumber (v: any): boolean {
11098
return typeof v === 'number'
11199
}
100+
101+
function scrollToPosition (shouldScroll, position) {
102+
const isObject = typeof shouldScroll === 'object'
103+
if (isObject && typeof shouldScroll.selector === 'string') {
104+
const el = document.querySelector(shouldScroll.selector)
105+
if (el) {
106+
let offset = shouldScroll.offset && typeof shouldScroll.offset === 'object' ? shouldScroll.offset : {}
107+
offset = normalizeOffset(offset)
108+
position = getElementPosition(el, offset)
109+
} else if (isValidPosition(shouldScroll)) {
110+
position = normalizePosition(shouldScroll)
111+
}
112+
} else if (isObject && isValidPosition(shouldScroll)) {
113+
position = normalizePosition(shouldScroll)
114+
}
115+
116+
if (position) {
117+
window.scrollTo(position.x, position.y)
118+
}
119+
}

0 commit comments

Comments
 (0)