|
1 | 1 | <script setup lang="ts"> |
2 | 2 | import SidebarItem from '@theme/SidebarItem.vue' |
| 3 | +import { watch } from 'vue' |
| 4 | +import { useRoute } from 'vue-router' |
3 | 5 | import { useSidebarItems } from '../composables' |
4 | 6 |
|
| 7 | +const route = useRoute() |
5 | 8 | const sidebarItems = useSidebarItems() |
| 9 | +
|
| 10 | +watch( |
| 11 | + () => route.hash, |
| 12 | + (hash) => { |
| 13 | + // get the sidebar DOM |
| 14 | + const sidebar = document.querySelector('.sidebar') |
| 15 | + if (!sidebar) return |
| 16 | +
|
| 17 | + // get the active sidebar item DOM, whose href equals to the current route |
| 18 | + const activeSidebarItem = document.querySelector( |
| 19 | + `.sidebar a.sidebar-item[href="${route.path}${hash}"]` |
| 20 | + ) |
| 21 | + if (!activeSidebarItem) return |
| 22 | +
|
| 23 | + // get the top and height of the sidebar |
| 24 | + const sidebarTop = sidebar.getBoundingClientRect().top |
| 25 | + const sidebarHeight = sidebar.getBoundingClientRect().height |
| 26 | +
|
| 27 | + // get the top and height of the active sidebar item |
| 28 | + const activeSidebarItemTop = activeSidebarItem.getBoundingClientRect().top |
| 29 | + const activeSidebarItemHeight = |
| 30 | + activeSidebarItem.getBoundingClientRect().height |
| 31 | +
|
| 32 | + if (activeSidebarItemTop < sidebarTop) { |
| 33 | + // scroll to the top edge of sidebar when the active sidebar item overflows the top edge of sidebar |
| 34 | + activeSidebarItem.scrollIntoView(true) |
| 35 | + } else if ( |
| 36 | + activeSidebarItemTop + activeSidebarItemHeight > |
| 37 | + sidebarTop + sidebarHeight |
| 38 | + ) { |
| 39 | + // scroll to the bottom edge of sidebar when the active sidebar item overflows the bottom edge of sidebar |
| 40 | + activeSidebarItem.scrollIntoView(false) |
| 41 | + } |
| 42 | + } |
| 43 | +) |
6 | 44 | </script> |
7 | 45 |
|
8 | 46 | <template> |
|
0 commit comments