Skip to content

Commit a7a5d9c

Browse files
committed
refactor: move scroll handling logic into util/scroll
1 parent 3f91065 commit a7a5d9c

File tree

3 files changed

+95
-93
lines changed

3 files changed

+95
-93
lines changed

src/history/html5.js

Lines changed: 7 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,10 @@
11
/* @flow */
22

3-
import type VueRouter from '../index'
4-
import { assert } from '../util/warn'
3+
import type Router from '../index'
4+
import { History } from './base'
55
import { inBrowser } from '../util/dom'
66
import { cleanPath } from '../util/path'
7-
import { History } from './base'
8-
import {
9-
saveScrollPosition,
10-
getScrollPosition,
11-
isValidPosition,
12-
normalizePosition,
13-
getElementPosition
14-
} from '../util/scroll-position'
7+
import { handleScroll, saveScrollPosition } from '../util/scroll'
158

169
// use User Timing api (if present) for more accurate key precision
1710
const Time = inBrowser && window.performance && window.performance.now
@@ -22,7 +15,7 @@ const genKey = () => String(Time.now())
2215
let _key: string = genKey()
2316

2417
export class HTML5History extends History {
25-
constructor (router: VueRouter, base: ?string) {
18+
constructor (router: Router, base: ?string) {
2619
super(router, base)
2720

2821
const expectScroll = router.options.scrollBehavior
@@ -31,7 +24,7 @@ export class HTML5History extends History {
3124
const current = this.current
3225
this.transitionTo(getLocation(this.base), next => {
3326
if (expectScroll) {
34-
this.handleScroll(next, current, true)
27+
handleScroll(router, _key, next, current, true)
3528
}
3629
})
3730
})
@@ -51,7 +44,7 @@ export class HTML5History extends History {
5144
const current = this.current
5245
this.transitionTo(location, route => {
5346
pushState(cleanPath(this.base + route.fullPath))
54-
this.handleScroll(route, current, false)
47+
handleScroll(this.router, _key, route, current, false)
5548
onComplete && onComplete(route)
5649
}, onAbort)
5750
}
@@ -60,7 +53,7 @@ export class HTML5History extends History {
6053
const current = this.current
6154
this.transitionTo(location, route => {
6255
replaceState(cleanPath(this.base + route.fullPath))
63-
this.handleScroll(route, current, false)
56+
handleScroll(this.router, _key, route, current, false)
6457
onComplete && onComplete(route)
6558
}, onAbort)
6659
}
@@ -75,45 +68,6 @@ export class HTML5History extends History {
7568
getCurrentLocation (): string {
7669
return getLocation(this.base)
7770
}
78-
79-
handleScroll (to: Route, from: Route, isPop: boolean) {
80-
const router = this.router
81-
if (!router.app) {
82-
return
83-
}
84-
85-
const behavior = router.options.scrollBehavior
86-
if (!behavior) {
87-
return
88-
}
89-
if (process.env.NODE_ENV !== 'production') {
90-
assert(typeof behavior === 'function', `scrollBehavior must be a function`)
91-
}
92-
93-
// wait until re-render finishes before scrolling
94-
router.app.$nextTick(() => {
95-
let position = getScrollPosition(_key)
96-
const shouldScroll = behavior(to, from, isPop ? position : null)
97-
if (!shouldScroll) {
98-
return
99-
}
100-
const isObject = typeof shouldScroll === 'object'
101-
if (isObject && typeof shouldScroll.selector === 'string') {
102-
const el = document.querySelector(shouldScroll.selector)
103-
if (el) {
104-
position = getElementPosition(el)
105-
} else if (isValidPosition(shouldScroll)) {
106-
position = normalizePosition(shouldScroll)
107-
}
108-
} else if (isObject && isValidPosition(shouldScroll)) {
109-
position = normalizePosition(shouldScroll)
110-
}
111-
112-
if (position) {
113-
window.scrollTo(position.x, position.y)
114-
}
115-
})
116-
}
11771
}
11872

11973
export function getLocation (base: string): string {

src/util/scroll-position.js

Lines changed: 0 additions & 40 deletions
This file was deleted.

src/util/scroll.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/* @flow */
2+
3+
import type Router from '../index'
4+
import { assert } from './warn'
5+
6+
const positionStore = Object.create(null)
7+
8+
export function handleScroll (
9+
router: Router,
10+
key: string,
11+
to: Route,
12+
from: Route,
13+
isPop: boolean
14+
) {
15+
if (!router.app) {
16+
return
17+
}
18+
19+
const behavior = router.options.scrollBehavior
20+
if (!behavior) {
21+
return
22+
}
23+
24+
if (process.env.NODE_ENV !== 'production') {
25+
assert(typeof behavior === 'function', `scrollBehavior must be a function`)
26+
}
27+
28+
// wait until re-render finishes before scrolling
29+
router.app.$nextTick(() => {
30+
let position = getScrollPosition(key)
31+
const shouldScroll = behavior(to, from, isPop ? position : null)
32+
if (!shouldScroll) {
33+
return
34+
}
35+
const isObject = typeof shouldScroll === 'object'
36+
if (isObject && typeof shouldScroll.selector === 'string') {
37+
const el = document.querySelector(shouldScroll.selector)
38+
if (el) {
39+
position = getElementPosition(el)
40+
} else if (isValidPosition(shouldScroll)) {
41+
position = normalizePosition(shouldScroll)
42+
}
43+
} else if (isObject && isValidPosition(shouldScroll)) {
44+
position = normalizePosition(shouldScroll)
45+
}
46+
47+
if (position) {
48+
window.scrollTo(position.x, position.y)
49+
}
50+
})
51+
}
52+
53+
export function saveScrollPosition (key: string) {
54+
if (!key) return
55+
positionStore[key] = {
56+
x: window.pageXOffset,
57+
y: window.pageYOffset
58+
}
59+
}
60+
61+
function getScrollPosition (key: string): ?Object {
62+
if (!key) return
63+
return positionStore[key]
64+
}
65+
66+
function getElementPosition (el: Element): Object {
67+
const docRect = document.documentElement.getBoundingClientRect()
68+
const elRect = el.getBoundingClientRect()
69+
return {
70+
x: elRect.left - docRect.left,
71+
y: elRect.top - docRect.top
72+
}
73+
}
74+
75+
function isValidPosition (obj: Object): boolean {
76+
return isNumber(obj.x) || isNumber(obj.y)
77+
}
78+
79+
function normalizePosition (obj: Object): Object {
80+
return {
81+
x: isNumber(obj.x) ? obj.x : window.pageXOffset,
82+
y: isNumber(obj.y) ? obj.y : window.pageYOffset
83+
}
84+
}
85+
86+
function isNumber (v: any): boolean {
87+
return typeof v === 'number'
88+
}

0 commit comments

Comments
 (0)