Files
test1/components/html-editor/hooks/useToolPostion.ts
2026-03-20 07:33:46 +00:00

83 lines
2.5 KiB
TypeScript
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 { HTMLEditor } from '../lib'
import { useEffect, useRef, useState } from 'react'
export const useToolPostion = (editor: HTMLEditor | null, isDoc: boolean) => {
const [position, setPosition] = useState<{ left: number; top: number, bottom: number, right: number, width: number, height: number } | null>(null)
// 标识是否从编辑器内开始选择
const isSelectingRef = useRef(false)
const updatePositionFromSelection = () => {
if (!editor) {
return
}
const view = editor.getDoc().view
if (!view) {
return
}
const selection = view.getSelection()
if (!selection) return
// 如果选区为空,不需要更新
const hasSelectAnything = selection.rangeCount === 0 || selection.toString().trim() === ''
if (selection.isCollapsed || selection.rangeCount === 0 || hasSelectAnything) {
setPosition(null)
return
}
// 获取选区的 Range 对象
const range = selection.getRangeAt(0);
// 获取选区末尾的位置
// 创建一个新的 Range只包含选区的末尾点
const endRange = range.cloneRange();
endRange.collapse(false); // false 表示折叠到末尾
const rect = endRange.getBoundingClientRect();
const { top, left, bottom, right, width, height } = rect
setPosition({ top, left, bottom, right, width, height })
}
useEffect(() => {
if (!editor || !isDoc) {
return
}
const dom = editor.getDoc().document
if (!dom) {
return
}
const onMouseDown = () => {
isSelectingRef.current = true
}
const onMouseUp = () => {
// 只有从编辑器内开始选择时才处理
if (!isSelectingRef.current) {
return
}
isSelectingRef.current = false
setTimeout(() => {
updatePositionFromSelection()
}, 50)
}
const onScrollOrResize = () => {
updatePositionFromSelection()
}
dom.addEventListener('mousedown', onMouseDown)
dom.addEventListener('mouseup', onMouseUp)
dom.addEventListener('scroll', onScrollOrResize)
window.addEventListener('scroll', onScrollOrResize, true)
window.addEventListener('resize', onScrollOrResize)
return () => {
dom.removeEventListener('mousedown', onMouseDown)
dom.removeEventListener('mouseup', onMouseUp)
dom.removeEventListener('scroll', onScrollOrResize)
window.removeEventListener('scroll', onScrollOrResize, true)
window.removeEventListener('resize', onScrollOrResize)
}
}, [editor, updatePositionFromSelection, isDoc])
return position
}