82 lines
2.1 KiB
Vue
82 lines
2.1 KiB
Vue
<script setup lang="ts">
|
|
import { useSidebarItems } from '@theme/useSidebarItems'
|
|
import VPSidebarItem from '@theme/VPSidebarItem.vue'
|
|
import { onMounted, watch } from 'vue'
|
|
import { useRoute } from 'vuepress/client'
|
|
|
|
const route = useRoute()
|
|
const sidebarItems = useSidebarItems()
|
|
|
|
onMounted(() => {
|
|
watch(
|
|
() => route.hash,
|
|
(hash) => {
|
|
// get the sidebar DOM
|
|
const sidebar = document.querySelector('.vp-sidebar')
|
|
if (!sidebar) return
|
|
|
|
// get the active sidebar item DOM, whose href equals to the current route
|
|
const activeSidebarItem = document.querySelector(
|
|
`.vp-sidebar a.vp-sidebar-item[href="${route.path}${hash}"]`,
|
|
)
|
|
if (!activeSidebarItem) return
|
|
|
|
// get the top and height of the sidebar
|
|
const { top: sidebarTop, height: sidebarHeight } =
|
|
sidebar.getBoundingClientRect()
|
|
// get the top and height of the active sidebar item
|
|
const { top: activeSidebarItemTop, height: activeSidebarItemHeight } =
|
|
activeSidebarItem.getBoundingClientRect()
|
|
|
|
// when the active sidebar item overflows the top edge of sidebar
|
|
if (activeSidebarItemTop < sidebarTop) {
|
|
// scroll to the top edge of sidebar
|
|
activeSidebarItem.scrollIntoView(true)
|
|
}
|
|
// when the active sidebar item overflows the bottom edge of sidebar
|
|
else if (
|
|
activeSidebarItemTop + activeSidebarItemHeight >
|
|
sidebarTop + sidebarHeight
|
|
) {
|
|
// scroll to the bottom edge of sidebar
|
|
activeSidebarItem.scrollIntoView(false)
|
|
}
|
|
},
|
|
)
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<ul v-if="sidebarItems.length" class="vp-sidebar-items">
|
|
<VPSidebarItem
|
|
v-for="item in sidebarItems"
|
|
:key="`${item.text}${item.link}`"
|
|
:item="item"
|
|
/>
|
|
</ul>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
@import '../styles/variables';
|
|
|
|
.vp-sidebar-items {
|
|
margin: 0;
|
|
padding: 1.5rem 0;
|
|
list-style-type: none;
|
|
|
|
@media (max-width: $MQMobile) {
|
|
padding: 1rem 0;
|
|
}
|
|
|
|
ul {
|
|
margin: 0;
|
|
padding: 0;
|
|
list-style-type: none;
|
|
}
|
|
|
|
a {
|
|
display: inline-block;
|
|
}
|
|
}
|
|
</style>
|