diff --git a/components/CustomContextMenu.js b/components/CustomContextMenu.js index e85f321a..2d0634f6 100644 --- a/components/CustomContextMenu.js +++ b/components/CustomContextMenu.js @@ -1,9 +1,10 @@ import Link from 'next/link' import { useRouter } from 'next/router' -import { useEffect, useState, useRef } from 'react' +import { useEffect, useState, useRef, useLayoutEffect } from 'react' import { useGlobal } from '@/lib/global' import { saveDarkModeToCookies, THEMES } from '@/themes/theme' import BLOG from '@/blog.config' +import useWindowSize from '@/hooks/useWindowSize' /** * 自定义右键菜单 @@ -15,6 +16,9 @@ export default function CustomContextMenu(props) { const [show, setShow] = useState(false) const { isDarkMode, updateDarkMode, locale } = useGlobal() const menuRef = useRef(null) + const windowSize = useWindowSize() + const [width, setWidth] = useState(0) + const [height, setHeight] = useState(0) const { latestPosts } = props const router = useRouter() @@ -27,10 +31,18 @@ export default function CustomContextMenu(props) { router.push(`${BLOG.SUB_PATH}/${randomPost?.slug}`) } + useLayoutEffect(() => { + setWidth(menuRef.current.offsetWidth) + setHeight(menuRef.current.offsetHeight) + }, []) + useEffect(() => { const handleContextMenu = (event) => { event.preventDefault() - setPosition({ y: `${event.clientY}px`, x: `${event.clientX}px` }) + // 计算点击位置加菜单宽高是否超出屏幕,如果超出则贴边弹出 + const x = (event.clientX < windowSize.width - width) ? event.clientX : windowSize.width - width + const y = (event.clientY < windowSize.height - height) ? event.clientY : windowSize.height - height + setPosition({ y: `${y}px`, x: `${x}px` }) setShow(true) } @@ -47,7 +59,7 @@ export default function CustomContextMenu(props) { window.removeEventListener('contextmenu', handleContextMenu) window.removeEventListener('click', handleClick) } - }, []) + }, [windowSize]) function handleBack() { window.history.back() diff --git a/hooks/useWindowSize.ts b/hooks/useWindowSize.ts new file mode 100644 index 00000000..90f685c4 --- /dev/null +++ b/hooks/useWindowSize.ts @@ -0,0 +1,30 @@ +import { useEffect, useState } from 'react' + +interface WindowSize { + width: number, + height: number +} + +const useWindowSize = () => { + const [size, setSize] = useState({ + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight + }) + + useEffect(() => { + const onResize = () => { + setSize({ + width: document.documentElement.clientWidth, + height: document.documentElement.clientHeight + }) + } + onResize() + window.addEventListener('resize', onResize) + return () => { + window.removeEventListener('resize', onResize) + } + }, []) + return size +} + +export default useWindowSize