Files
NotionNext/themes/hexo/components/RightFloatArea.js
2025-04-16 10:00:48 +08:00

69 lines
2.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useCallback, useEffect, useState } from 'react'
import ButtonDarkModeFloat from './ButtonFloatDarkMode'
import ButtonJumpToTop from './ButtonJumpToTop'
/**
* 悬浮在右下角的按钮当页面向下滚动100px时会出现
* 当页面回到顶部时会隐藏
* @param {*} param0
* @returns
*/
export default function RightFloatArea({ floatSlot }) {
const [showFloatButton, switchShow] = useState(false)
const scrollListener = useCallback(() => {
const targetRef =
document.getElementById('wrapper') || document.documentElement
const clientHeight = targetRef?.clientHeight || 0
const scrollY =
window.pageYOffset || document.documentElement.scrollTop || 0
const viewportHeight =
window.innerHeight || document.documentElement.clientHeight || 0
const fullHeight = Math.max(1, clientHeight - viewportHeight)
let per = parseFloat(((scrollY / fullHeight) * 100).toFixed(0))
// 完整的边界处理
if (isNaN(per) || per < 0) per = 0
if (per > 100) per = 100
const shouldShow = scrollY > 100 && per > 0
// 右下角显示悬浮按钮
if (shouldShow !== showFloatButton) {
switchShow(shouldShow)
}
}, [showFloatButton])
useEffect(() => {
const throttledScroll = () => {
window.requestAnimationFrame(() => {
scrollListener()
})
}
window.addEventListener('scroll', throttledScroll)
// 初始调用一次检查初始状态
scrollListener()
return () => window.removeEventListener('scroll', throttledScroll)
}, [scrollListener])
return (
<div
className={
(showFloatButton ? 'opacity-100 ' : 'invisible opacity-0') +
' duration-300 transition-all bottom-12 right-1 fixed justify-end z-20 text-white bg-indigo-500 dark:bg-hexo-black-gray rounded-sm'
}>
<div
className={'justify-center flex flex-col items-center cursor-pointer'}>
<ButtonDarkModeFloat />
{floatSlot}
<ButtonJumpToTop />
</div>
</div>
)
}