Skip to content

Commit 62c3525

Browse files
committed
refactor($active-header-links): rewrite
1 parent 6f52012 commit 62c3525

File tree

1 file changed

+64
-35
lines changed

1 file changed

+64
-35
lines changed

packages/@vuepress/plugin-active-header-links/mixin.js

+64-35
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,76 @@
1-
import Vue from 'vue'
21
import throttle from 'lodash.throttle'
32

3+
function calculateCurrentAnchor (anchors) {
4+
const l = anchors.length
5+
if (anchors[0].top > 0 && anchors[0].top < 10) {
6+
return anchors[0]
7+
}
8+
9+
if (anchors[l - 1].top < 0) {
10+
return anchors[l - 1]
11+
}
12+
13+
for (let i = 0; i < l; i++) {
14+
const anchor = anchors[i]
15+
const nextAnchor = anchors[i + 1]
16+
if (anchor.top < 0 && nextAnchor.top > 0) {
17+
if (nextAnchor.top < 10) {
18+
return nextAnchor
19+
}
20+
return anchor
21+
}
22+
}
23+
24+
return anchors[0]
25+
}
26+
27+
function getAnchors () {
28+
const sidebarLinks = [].slice.call(document.querySelectorAll('.sidebar-link'))
29+
return [].slice
30+
.call(document.querySelectorAll('.header-anchor'))
31+
.filter(anchor => sidebarLinks.some(sidebarLink => sidebarLink.hash === anchor.hash))
32+
.map(el => {
33+
return {
34+
el,
35+
hash: decodeURIComponent(el.hash),
36+
top: el.getBoundingClientRect().top - 90
37+
/* 90 is to Subtract height of navbar & anchor's padding top */
38+
}
39+
})
40+
}
41+
442
export default {
543
mounted () {
6-
window.addEventListener('scroll', this.onScroll)
44+
this.$vuepress.$on('AsyncMarkdownContentLoaded', (slotKey) => {
45+
if (slotKey === 'default') {
46+
window.addEventListener('scroll', this.onScroll)
47+
}
48+
})
49+
50+
this.$vuepress.$on('AnchorHashChange', (anchor) => {
51+
// When user clicked sidebar links, we need to disable the scroll
52+
// event triggered.
53+
if (this.$route.hash === anchor.hash) {
54+
return
55+
}
56+
this.$vuepress.$set('disableScrollBehavior', true)
57+
this.$router.replace(decodeURIComponent(anchor.hash), () => {
58+
// execute after scrollBehavior handler.
59+
this.$nextTick(() => {
60+
this.$vuepress.$set('disableScrollBehavior', false)
61+
})
62+
})
63+
})
764
},
865

966
methods: {
1067
onScroll: throttle(function () {
11-
this.setActiveHash()
12-
}, 300),
13-
14-
setActiveHash () {
15-
const sidebarLinks = [].slice.call(document.querySelectorAll('.sidebar-link'))
16-
const anchors = [].slice.call(document.querySelectorAll('.header-anchor'))
17-
.filter(anchor => sidebarLinks.some(sidebarLink => sidebarLink.hash === anchor.hash))
18-
19-
const scrollTop = Math.max(
20-
window.pageYOffset,
21-
document.documentElement.scrollTop,
22-
document.body.scrollTop
23-
)
24-
25-
for (let i = 0; i < anchors.length; i++) {
26-
const anchor = anchors[i]
27-
const nextAnchor = anchors[i + 1]
28-
29-
const isActive = i === 0 && scrollTop === 0 ||
30-
(scrollTop >= anchor.parentElement.offsetTop + 10 &&
31-
(!nextAnchor || scrollTop < nextAnchor.parentElement.offsetTop - 10))
32-
33-
if (isActive && decodeURIComponent(this.$route.hash) !== decodeURIComponent(anchor.hash)) {
34-
Vue.$store.set('disableScrollBehavior', true)
35-
this.$router.replace(decodeURIComponent(anchor.hash), () => {
36-
// execute after scrollBehavior handler.
37-
this.$nextTick(() => {
38-
Vue.$store.set('disableScrollBehavior', false)
39-
})
40-
})
41-
return
42-
}
68+
this.$lastAnchor = this.$currentAnchor
69+
this.$currentAnchor = calculateCurrentAnchor(getAnchors())
70+
if (!this.$lastAnchor || this.$lastAnchor.hash !== this.$currentAnchor.hash) {
71+
this.$vuepress.$emit('AnchorHashChange', this.$currentAnchor)
4372
}
44-
}
73+
}, 300)
4574
},
4675

4776
beforeDestroy () {

0 commit comments

Comments
 (0)