目录自动滚动细节

This commit is contained in:
tangly1024.com
2024-09-18 10:07:09 +08:00
parent ea4dacad18
commit 8332e97b71
5 changed files with 69 additions and 41 deletions

View File

@@ -1,6 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData'
import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents'
import { uploadDataToAlgolia } from '@/lib/plugins/algolia'
import { checkSlugHasMorThanTwoSlash, getRecommendPost } from '@/lib/utils/post'
import { idToUuid } from 'notion-utils'
@@ -97,6 +98,15 @@ export async function getStaticProps({
if (!props?.post?.blockMap) {
props.post.blockMap = await getPostBlocks(props.post.id, from)
}
// 目录默认加载
if (props.post?.blockMap?.block) {
props.post.content = Object.keys(props.post.blockMap.block).filter(
key => props.post.blockMap.block[key]?.value?.parent_id === props.post.id
)
props.post.toc = getPageTableOfContents(props.post, props.post.blockMap)
}
// 生成全文索引 && JSON.parse(BLOG.ALGOLIA_RECREATE_DATA)
if (BLOG.ALGOLIA_APP_ID) {
uploadDataToAlgolia(props?.post)

View File

@@ -1,6 +1,7 @@
import BLOG from '@/blog.config'
import { siteConfig } from '@/lib/config'
import { getGlobalData, getPost, getPostBlocks } from '@/lib/db/getSiteData'
import { getPageTableOfContents } from '@/lib/notion/getPageTableOfContents'
import { uploadDataToAlgolia } from '@/lib/plugins/algolia'
import { checkSlugHasOneSlash, getRecommendPost } from '@/lib/utils/post'
import { idToUuid } from 'notion-utils'
@@ -86,6 +87,15 @@ export async function getStaticProps({ params: { prefix, slug }, locale }) {
if (!props?.post?.blockMap) {
props.post.blockMap = await getPostBlocks(props.post.id, from)
}
// 目录默认加载
if (props.post?.blockMap?.block) {
props.post.content = Object.keys(props.post.blockMap.block).filter(
key => props.post.blockMap.block[key]?.value?.parent_id === props.post.id
)
props.post.toc = getPageTableOfContents(props.post, props.post.blockMap)
}
// 生成全文索引 && JSON.parse(BLOG.ALGOLIA_RECREATE_DATA)
if (BLOG.ALGOLIA_APP_ID) {
uploadDataToAlgolia(props?.post)

View File

@@ -55,12 +55,6 @@ const Slug = props => {
setLock(true)
} else {
setLock(false)
if (!lock && post?.blockMap?.block) {
post.content = Object.keys(post.blockMap.block).filter(
key => post.blockMap.block[key]?.value?.parent_id === post.id
)
post.toc = getPageTableOfContents(post, post.blockMap)
}
}
// 读取上次记录 自动提交密码
@@ -171,6 +165,14 @@ export async function getStaticProps({ params: { prefix }, locale }) {
props.post.blockMap = await getPostBlocks(props.post.id, from)
}
// 目录默认加载
if (props.post?.blockMap?.block) {
props.post.content = Object.keys(props.post.blockMap.block).filter(
key => props.post.blockMap.block[key]?.value?.parent_id === props.post.id
)
props.post.toc = getPageTableOfContents(props.post, props.post.blockMap)
}
// 生成全文索引 && process.env.npm_lifecycle_event === 'build' && JSON.parse(BLOG.ALGOLIA_RECREATE_DATA)
if (BLOG.ALGOLIA_APP_ID) {
uploadDataToAlgolia(props?.post)

View File

@@ -1,6 +1,6 @@
import throttle from 'lodash.throttle'
import { uuidToId } from 'notion-utils'
import { useCallback, useEffect, useRef, useState } from 'react'
import { useEffect, useRef, useState } from 'react'
import Progress from './Progress'
/**
@@ -9,7 +9,7 @@ import Progress from './Progress'
* @returns {JSX.Element}
* @constructor
*/
const Catalog = ({ toc, className }) => {
const Catalog = ({ post, toc, className }) => {
const tocIds = []
// 目录自动滚动
@@ -19,43 +19,45 @@ const Catalog = ({ toc, className }) => {
// 监听滚动事件
useEffect(() => {
window.addEventListener('scroll', actionSectionScrollSpy)
actionSectionScrollSpy()
if (toc && toc.length > 1) {
actionSectionScrollSpy()
window.addEventListener('scroll', actionSectionScrollSpy)
}
setTimeout(() => {
console.log('目录', post, toc)
}, 1000)
return () => {
window.removeEventListener('scroll', actionSectionScrollSpy)
}
}, [])
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
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')
}
setActiveSection(currentSectionId)
const index = tocIds.indexOf(currentSectionId) || 0
tRef?.current?.scrollTo({ top: 28 * index, behavior: 'smooth' })
console.log(tRef?.current)
}, throttleMs)
)
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) {
@@ -68,10 +70,10 @@ const Catalog = ({ toc, className }) => {
<Progress />
</div>
<div
className='overflow-y-auto scroll-hidden lg:max-h-dvh max-h-44'
className='overflow-y-auto scroll-hidden lg:max-h-96 max-h-44'
ref={tRef}>
<nav className='h-full text-black'>
{toc.map(tocItem => {
{toc?.map(tocItem => {
const id = uuidToId(tocItem.id)
tocIds.push(id)
return (

View File

@@ -189,7 +189,11 @@ const LayoutSlug = props => {
{/* 文章区块分为三列 */}
<div className='grid grid-cols-1 lg:grid-cols-5 gap-8 py-12'>
<div className='h-full lg:col-span-1 hidden lg:block'>
<Catalog toc={post?.toc} className='sticky top-20' />
<Catalog
post={post}
toc={post?.toc || []}
className='sticky top-20'
/>
</div>
{/* Notion文章主体 */}