Skip to content

Commit f3b506f

Browse files
author
Mate Solymosi
committed
feat(scroll): smarter scroll behavior
1 parent 6ac7bac commit f3b506f

File tree

6 files changed

+49
-15
lines changed

6 files changed

+49
-15
lines changed

Diff for: src/core/event/index.js

+18-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
11
import {isMobile} from '../util/env'
22
import {body, on} from '../util/dom'
33
import * as sidebar from './sidebar'
4-
import {scrollIntoView} from './scroll'
4+
import {scrollIntoView, scroll2Top} from './scroll'
55

66
export function eventMixin(proto) {
7-
proto.$resetEvents = function () {
8-
scrollIntoView(this.route.path, this.route.query.id)
7+
proto.$resetEvents = function (source) {
8+
const {auto2top} = this.config
9+
10+
;(() => {
11+
// Rely on the browser's scroll auto-restoration when going back or forward
12+
if (source === 'history') {
13+
return
14+
}
15+
// Scroll to ID if specified
16+
if (this.route.query.id) {
17+
scrollIntoView(this.route.path, this.route.query.id)
18+
}
19+
// Scroll to top if a link was clicked and auto2top is enabled
20+
if (source === 'navigate') {
21+
auto2top && scroll2Top(auto2top)
22+
}
23+
})();
924

1025
if (this.config.loadNavbar) {
1126
sidebar.getAndActive(this.router, 'nav')

Diff for: src/core/fetch/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ export function fetchMixin(proto) {
144144
}
145145
}
146146

147-
proto.$fetch = function (cb = noop) {
147+
proto.$fetch = function (cb = noop, $resetEvents = this.$resetEvents.bind(this)) {
148148
const done = () => {
149149
callHook(this, 'doneEach')
150150
cb()
@@ -156,7 +156,7 @@ export function fetchMixin(proto) {
156156
done()
157157
} else {
158158
this._fetch(() => {
159-
this.$resetEvents()
159+
$resetEvents();
160160
done()
161161
})
162162
}

Diff for: src/core/render/index.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {getAndActive, sticky} from '../event/sidebar'
88
import {getPath, isAbsolutePath} from '../router/util'
99
import {isMobile, inBrowser} from '../util/env'
1010
import {isPrimitive} from '../util/core'
11-
import {scrollActiveSidebar, scroll2Top} from '../event/scroll'
11+
import {scrollActiveSidebar} from '../event/scroll'
1212
import {prerenderEmbed} from './embed'
1313

1414
function executeScript() {
@@ -107,7 +107,7 @@ export function renderMixin(proto) {
107107
}
108108

109109
proto._bindEventOnRendered = function (activeEl) {
110-
const {autoHeader, auto2top} = this.config
110+
const {autoHeader} = this.config
111111

112112
scrollActiveSidebar(this.router)
113113

@@ -120,8 +120,6 @@ export function renderMixin(proto) {
120120
dom.before(main, h1)
121121
}
122122
}
123-
124-
auto2top && scroll2Top(auto2top)
125123
}
126124

127125
proto._renderNav = function (text) {

Diff for: src/core/router/history/hash.js

+19-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,25 @@ export class HashHistory extends History {
3030
}
3131

3232
onchange(cb = noop) {
33-
on('hashchange', cb)
33+
// The hashchange event does not tell us if it originated from
34+
// a clicked link or by moving back/forward in the history;
35+
// therefore we set a `navigating` flag when a link is clicked
36+
// to be able to tell these two scenarios apart
37+
let navigating = false
38+
39+
on('click', e => {
40+
const el = e.target.tagName === 'A' ? e.target : e.target.parentNode
41+
42+
if (el.tagName === 'A' && !/_blank/.test(el.target)) {
43+
navigating = true
44+
}
45+
})
46+
47+
on('hashchange', e => {
48+
const source = navigating ? 'navigate' : 'history'
49+
navigating = false
50+
cb({event: e, source})
51+
})
3452
}
3553

3654
normalize() {

Diff for: src/core/router/history/html5.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ export class HTML5History extends History {
2828
e.preventDefault()
2929
const url = el.href
3030
window.history.pushState({key: url}, '', url)
31-
cb()
31+
cb({event: e, source: 'navigate'})
3232
}
3333
})
3434

35-
on('popstate', cb)
35+
on('popstate', e => {
36+
cb({event: e, source: 'history'})
37+
})
3638
}
3739

3840
/**

Diff for: src/core/router/index.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {HashHistory} from './history/hash'
22
import {HTML5History} from './history/html5'
33
import {supportsPushState} from '../util/env'
4+
import {noop} from '../util/core'
45
import * as dom from '../util/dom'
56

67
export function routerMixin(proto) {
@@ -30,16 +31,16 @@ export function initRouter(vm) {
3031
updateRender(vm)
3132
lastRoute = vm.route
3233

33-
router.onchange(_ => {
34+
router.onchange(params => {
3435
updateRender(vm)
3536
vm._updateRender()
3637

3738
if (lastRoute.path === vm.route.path) {
38-
vm.$resetEvents()
39+
vm.$resetEvents(params.source)
3940
return
4041
}
4142

42-
vm.$fetch()
43+
vm.$fetch(noop, vm.$resetEvents.bind(vm, params.source))
4344
lastRoute = vm.route
4445
})
4546
}

0 commit comments

Comments
 (0)