feat(theme): 侧边栏自动定位到当前活动项
This commit is contained in:
parent
a0eac82f4e
commit
e395e98128
@ -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>
|
||||
|
||||
@ -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>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user