From e75a3f0b34537fee4db8d915dd3ccfa89ff34730 Mon Sep 17 00:00:00 2001 From: Just4fun2021 Date: Sat, 1 Apr 2023 12:09:00 +0800 Subject: [PATCH] fix catalog auto scroll --- themes/fukasawa/components/Catalog.js | 71 +++++++++++++------------- themes/simple/components/Catalog.js | 73 +++++++++++++-------------- 2 files changed, 69 insertions(+), 75 deletions(-) diff --git a/themes/fukasawa/components/Catalog.js b/themes/fukasawa/components/Catalog.js index ff5782be..4a5414d2 100644 --- a/themes/fukasawa/components/Catalog.js +++ b/themes/fukasawa/components/Catalog.js @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import throttle from 'lodash.throttle' import { uuidToId } from 'notion-utils' import { useGlobal } from '@/lib/global' @@ -12,51 +12,51 @@ import { useGlobal } from '@/lib/global' const Catalog = ({ toc }) => { const { locale } = useGlobal() + // 同步选中目录事件 + const [activeSection, setActiveSection] = useState(null) + // 监听滚动事件 useEffect(() => { - window.addEventListener('scroll', actionSectionScrollSpy) + const throttleMs = 200 + const actionSectionScrollSpy = throttle(() => { + const sections = document.getElementsByClassName('notion-h') + let prevBBox = null + let currentSectionId = activeSection + for (let i = 0; i < sections.length; ++i) { + const section = sections[i] + if (!section || !(section instanceof Element)) continue + if (!currentSectionId) { + currentSectionId = section.getAttribute('data-id') + } + const bbox = section.getBoundingClientRect() + const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0 + const offset = Math.max(150, prevHeight / 4) + // GetBoundingClientRect returns values relative to viewport + if (bbox.top - offset < 0) { + currentSectionId = section.getAttribute('data-id') + prevBBox = bbox + continue + } + // No need to continue loop, if last element has been detected + break + } + setActiveSection(currentSectionId) + const index = toc?.findIndex(obj => uuidToId(obj.id) === currentSectionId) + tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) + }, throttleMs) + actionSectionScrollSpy() + window.addEventListener('scroll', actionSectionScrollSpy) return () => { window.removeEventListener('scroll', actionSectionScrollSpy) } - }, []) + }, [toc]) // 目录自动滚动 const tRef = useRef(null) - const tocIds = [] - - // 同步选中目录事件 - const [activeSection, setActiveSection] = useState(null) - const throttleMs = 200 - const actionSectionScrollSpy = useCallback(throttle(() => { - const sections = document.getElementsByClassName('notion-h') - let prevBBox = null - let currentSectionId = activeSection - for (let i = 0; i < sections.length; ++i) { - const section = sections[i] - if (!section || !(section instanceof Element)) continue - if (!currentSectionId) { - currentSectionId = section.getAttribute('data-id') - } - const bbox = section.getBoundingClientRect() - const prevHeight = prevBBox ? bbox.top - prevBBox.bottom : 0 - const offset = Math.max(150, prevHeight / 4) - // GetBoundingClientRect returns values relative to viewport - if (bbox.top - offset < 0) { - currentSectionId = section.getAttribute('data-id') - prevBBox = bbox - continue - } - // No need to continue loop, if last element has been detected - break - } - setActiveSection(currentSectionId) - const index = tocIds.indexOf(currentSectionId) || 0 - tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' }) - }, throttleMs)) // 无目录就直接返回空 - if (!toc || toc.length < 1) { + if (!toc || toc?.length < 1) { return <> } @@ -66,7 +66,6 @@ const Catalog = ({ toc }) => {