-
Notifications
You must be signed in to change notification settings - Fork 4.7k
/
Copy pathmixin.js
101 lines (89 loc) · 2.71 KB
/
mixin.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/* global AHL_SIDEBAR_LINK_SELECTOR, AHL_HEADER_ANCHOR_SELECTOR, AHL_TOP_OFFSET */
import throttle from 'lodash.throttle'
function calculateCurrentAnchor (anchors) {
const l = anchors.length
if (anchors[0].top > 0 && anchors[0].top < 10) {
return anchors[0]
}
if (anchors[l - 1].top < 0) {
return anchors[l - 1]
}
for (let i = 0; i < l; i++) {
const anchor = anchors[i]
const nextAnchor = anchors[i + 1]
if (anchor.top < 0 && nextAnchor.top > 0) {
if (nextAnchor.top < 10) {
return nextAnchor
}
return anchor
}
}
return anchors[0]
}
function getAnchors () {
const sidebarLinks = [].slice.call(document.querySelectorAll(AHL_SIDEBAR_LINK_SELECTOR))
return [].slice
.call(document.querySelectorAll(AHL_HEADER_ANCHOR_SELECTOR))
.filter(anchor => sidebarLinks.some(sidebarLink => sidebarLink.hash === anchor.hash))
.map(el => {
return {
el,
hash: decodeURIComponent(el.hash),
top: el.getBoundingClientRect().top - AHL_TOP_OFFSET
/* AHL_TOP_OFFSET is to Subtract height of navbar & anchor's padding top */
}
})
}
let freezeScrollEvent = true
export default {
mounted () {
this.$router.beforeEach((to, from, next) => {
if (to.path !== from.path) {
freezeScrollEvent = true
}
next()
})
this.$vuepress.$on('AsyncMarkdownContentMounted', (slotKey) => {
// delay activation of scroll event
setTimeout(() => {
freezeScrollEvent = false
}, 1000)
if (slotKey === 'default') {
window.addEventListener('scroll', () => this.onScroll(freezeScrollEvent))
}
})
this.$vuepress.$on('AnchorHashChange', (anchor) => {
// When user clicked sidebar links, we need to disable the scroll
// event triggered.
if (this.$route.hash === anchor.hash) {
return
}
this.$vuepress.$set('disableScrollBehavior', true)
this.$router.replace(decodeURIComponent(anchor.hash), () => {
// execute after scrollBehavior handler.
this.$nextTick(() => {
this.$vuepress.$set('disableScrollBehavior', false)
})
})
})
},
methods: {
onScroll: throttle(function (freezeScrollEvent) {
if (freezeScrollEvent) {
return
}
const anchors = getAnchors()
if (anchors.length === 0) {
return
}
this.$lastAnchor = this.$currentAnchor
this.$currentAnchor = calculateCurrentAnchor(anchors)
if (!this.$lastAnchor || this.$lastAnchor.hash !== this.$currentAnchor.hash) {
this.$vuepress.$emit('AnchorHashChange', this.$currentAnchor)
}
}, 300)
},
beforeDestroy () {
window.removeEventListener('scroll', this.onScroll)
}
}