feat(theme): 侧边栏自动定位到当前活动项

This commit is contained in:
pengzhanbo 2024-06-05 00:33:46 +08:00
parent a0eac82f4e
commit e395e98128
2 changed files with 48 additions and 3 deletions

View File

@ -1,5 +1,6 @@
<script lang="ts" setup>
import { computed } from 'vue'
import { computed, nextTick, ref, watch } from 'vue'
import { useRoute } from 'vuepress/client'
import { useData, useSidebar } from '../composables/index.js'
import { usePageEncrypt } from '../composables/encrypt.js'
import PageAside from './PageAside.vue'
@ -10,6 +11,7 @@ import TransitionFadeSlideY from './TransitionFadeSlideY.vue'
const { hasSidebar, hasAside } = useSidebar()
const { page, isDark } = useData()
const route = useRoute()
const { isPageDecrypted } = usePageEncrypt()
@ -23,6 +25,32 @@ const enableAside = computed(() => {
return hasAside.value && isPageDecrypted.value
})
const asideEl = ref<HTMLElement>()
watch(
() => route.hash,
hash =>
nextTick(() => {
if (!asideEl.value)
return
const activeItem = asideEl.value.querySelector(
`.outline-link[href="${hash}"]`,
)
if (!activeItem || !hash) {
asideEl.value.scrollTop = 0
return
}
const { top: navTop, height: navHeight }
= asideEl.value.getBoundingClientRect()
const { top: activeTop, height: activeHeight }
= activeItem.getBoundingClientRect()
if (activeTop < navTop || activeTop + activeHeight > navTop + navHeight)
activeItem.scrollIntoView({ block: 'center' })
}),
{ immediate: true },
)
</script>
<template>
@ -37,7 +65,7 @@ const enableAside = computed(() => {
>
<div class="container">
<div v-if="enableAside" class="aside">
<div class="aside-container">
<div ref="asideEl" class="aside-container">
<div class="aside-content">
<PageAside />
</div>

View File

@ -1,6 +1,7 @@
<script lang="ts" setup>
import { useScrollLock } from '@vueuse/core'
import { ref, watch } from 'vue'
import { onMounted, ref, watch } from 'vue'
import { useRoutePath } from 'vuepress/client'
import { useSidebar } from '../composables/sidebar.js'
import { inBrowser } from '../utils/index.js'
import SidebarItem from './SidebarItem.vue'
@ -11,6 +12,7 @@ const props = defineProps<{
}>()
const { sidebarGroups, hasSidebar, sidebarKey } = useSidebar()
const routePath = useRoutePath()
// a11y: focus Nav element when menu has opened
const navEl = ref<HTMLElement | null>(null)
@ -27,6 +29,21 @@ watch(
},
{ immediate: true, flush: 'post' },
)
onMounted(() => {
const activeItem = document.querySelector(
`.sidebar-wrapper .auto-link[href*="${routePath.value}"]`,
)
if (!activeItem || !navEl.value)
return
const { top: navTop, height: navHeight } = navEl.value.getBoundingClientRect()
const { top: activeTop, height: activeHeight }
= activeItem.getBoundingClientRect()
if (activeTop < navTop || activeTop + activeHeight > navTop + navHeight)
activeItem.scrollIntoView({ block: 'center' })
})
</script>
<template>