diff --git a/plugins/scroll-reset.client.ts b/plugins/scroll-reset.client.ts new file mode 100644 index 0000000..08983e3 --- /dev/null +++ b/plugins/scroll-reset.client.ts @@ -0,0 +1,44 @@ +export default defineNuxtPlugin(() => { + if (typeof window === 'undefined') return + + let observer: IntersectionObserver | null = null + let headings: HTMLElement[] = [] + + function initScrollSpy() { + // 清理旧的 observer + if (observer) observer.disconnect() + + // 收集所有带 id 的标题 + headings = Array.from(document.querySelectorAll('.prose h2[id], .prose h3[id]')) as HTMLElement[] + if (headings.length === 0) return + + observer = new IntersectionObserver( + (entries) => { + for (const entry of entries) { + if (entry.isIntersecting) { + const id = entry.target.getAttribute('id') + if (id) { + history.replaceState(null, '', `#${id}`) + } + } + } + }, + { rootMargin: '-80px 0px -70% 0px' } + ) + + headings.forEach(h => observer!.observe(h)) + } + + // 路由切换后重新初始化 + const router = useRouter() + router.afterEach(() => { + nextTick(() => { + setTimeout(initScrollSpy, 100) + }) + }) + + // 首次加载 + onMounted(() => { + setTimeout(initScrollSpy, 100) + }) +})