学校要求教师在他的本职工作上成为一种艺术家。 —— 爱因斯坦

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
import { DomEditor, IDomEditor, SlateEditor, SlateTransforms } from '@wangeditor/editor'

function addMouseHoverListener(editor: IDomEditor) {
const editorElement = DomEditor.toDOMNode(editor, editor)

let hoverTimeout: NodeJS.Timeout | null = null // 用于存储定时器
let lastHoveredOffset: { x: number; y: number } | null = null // 用于记录上次鼠标悬停的位置

editorElement.addEventListener('mousemove', event => {
const { clientX, clientY } = event

// 如果鼠标位置与上次相同,直接返回
if (lastHoveredOffset && lastHoveredOffset.x === clientX && lastHoveredOffset.y === clientY) {
return
}

// 更新鼠标位置
lastHoveredOffset = { x: clientX, y: clientY }

// 清除之前的定时器
if (hoverTimeout) {
clearTimeout(hoverTimeout)
hoverTimeout = null
}

// 设置新的定时器(延时 1 秒触发选中逻辑)
hoverTimeout = setTimeout(() => {
// @ts-ignore
const domCaretPosition = document.caretPositionFromPoint?.(clientX, clientY)
const domRange = domCaretPosition
? document.createRange()
: document.caretRangeFromPoint?.(clientX, clientY)

if (domCaretPosition && domRange) {
domRange.setStart(domCaretPosition.offsetNode, domCaretPosition.offset)
domRange.collapse(true)
}

if (!domRange) return

const slateNode = DomEditor.toSlateNode(editor, domRange.startContainer)
const slatePath = DomEditor.findPath(editor, slateNode)

// 获取当前节点的内容
const nodeText = SlateEditor.string(editor, slatePath)

// 判断鼠标所在位置的偏移量
const offset = domCaretPosition?.offset || domRange.startOffset

// 支持的句子分隔符,包括中文标点符号和西文标点符号
const sentenceSeparators = ['。', '?', '!', '.', '?', '!']

// 找到句子的起点
const sentenceStart = (() => {
let start = 0
for (const sep of sentenceSeparators) {
const index = nodeText.lastIndexOf(sep, offset - 1)
if (index !== -1) {
start = Math.max(start, index + 1) // 分隔符后一个字符是句子的开头
}
}
return start
})()

// 找到句子的终点
const sentenceEnd = (() => {
let end = nodeText.length
for (const sep of sentenceSeparators) {
const index = nodeText.indexOf(sep, offset)
if (index !== -1) {
end = Math.min(end, index + 1) // 分隔符本身是句子的结尾
}
}
return end
})()

// 定义选区范围
const range = {
anchor: { path: slatePath, offset: sentenceStart },
focus: { path: slatePath, offset: sentenceEnd },
}

// 确保编辑器被聚焦
if (!editor.isFocused()) {
editor.focus()
}

// 设置选区
SlateTransforms.select(editor, range)
}, 500) // 延时 1 秒
})

// 在鼠标移出编辑器时清除定时器
editorElement.addEventListener('mouseleave', () => {
if (hoverTimeout) {
clearTimeout(hoverTimeout)
hoverTimeout = null
}
lastHoveredOffset = null
})
}

export default addMouseHoverListener

注册就是

1
2
3
import addMouseMoveListener from './auto-select-sentence'

addMouseMoveListener(editor)