2025-01-15 16:35:20 +08:00
|
|
|
|
export const cursors = []
|
|
|
|
|
|
|
|
|
|
export class Cursor {
|
|
|
|
|
constructor(targetNode = null, insertIndex = null) {
|
|
|
|
|
this.targetNode = targetNode // 初始时可以直接指定目标文本节点
|
|
|
|
|
this.insertIndex = insertIndex // 初始时可以直接指定插入位置索引
|
|
|
|
|
this.range = document.createRange()
|
|
|
|
|
this.cursorElement = this.createCursorElement()
|
|
|
|
|
document.body.appendChild(this.cursorElement)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建光标元素
|
|
|
|
|
createCursorElement() {
|
|
|
|
|
const cursorElement = document.createElement("div")
|
|
|
|
|
Object.assign(cursorElement.style, {
|
|
|
|
|
position: "absolute",
|
|
|
|
|
width: "2px",
|
|
|
|
|
height: "1em",
|
|
|
|
|
backgroundColor: "black",
|
|
|
|
|
zIndex: "9999",
|
|
|
|
|
pointerEvents: "none",
|
|
|
|
|
display: "none", // 初始隐藏
|
|
|
|
|
transition: "all 0.1s ease"
|
|
|
|
|
})
|
|
|
|
|
return cursorElement
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置目标文本节点和插入位置
|
|
|
|
|
setTarget(node, index) {
|
|
|
|
|
this.targetNode = node
|
|
|
|
|
this.insertIndex = index
|
|
|
|
|
this.updateRange()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新范围
|
|
|
|
|
updateRange() {
|
|
|
|
|
if (this.targetNode && this.insertIndex !== null) {
|
|
|
|
|
this.range.setStart(this.targetNode, this.insertIndex)
|
|
|
|
|
this.range.setEnd(this.targetNode, this.insertIndex)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 插入文本
|
|
|
|
|
insertText(text) {
|
|
|
|
|
const insertionNode = document.createTextNode(text)
|
|
|
|
|
this.updateRange()
|
|
|
|
|
this.range.insertNode(insertionNode)
|
|
|
|
|
// 更新插入位置
|
|
|
|
|
this.insertIndex += text.length
|
|
|
|
|
this.updateRange() // 更新光标范围
|
|
|
|
|
return insertionNode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 获取当前光标的矩形位置
|
|
|
|
|
getBoundingClientRect() {
|
|
|
|
|
this.updateRange()
|
|
|
|
|
return this.range.getBoundingClientRect()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新光标位置
|
|
|
|
|
updatePosition(rect) {
|
|
|
|
|
if (!rect) {
|
|
|
|
|
this.hide()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
this.cursorElement.style.left = `${rect.left}px`
|
|
|
|
|
this.cursorElement.style.top = `${rect.top}px`
|
|
|
|
|
this.cursorElement.style.display = "block"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 隐藏光标
|
|
|
|
|
hide() {
|
|
|
|
|
this.cursorElement.style.display = "none"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 移除光标元素
|
|
|
|
|
remove() {
|
|
|
|
|
this.cursorElement.remove()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
move(key) {
|
|
|
|
|
// 获取目标节点的上下兄弟节点(li元素)
|
|
|
|
|
const children = Array.from(this.targetNode.parentNode.parentNode.children)
|
|
|
|
|
const siblings = children.filter(node => {
|
|
|
|
|
return node !== this.targetNode && node.nodeType === Node.ELEMENT_NODE
|
|
|
|
|
}).map(item => {
|
|
|
|
|
return Array.from(item.childNodes).find(node => node.nodeType === Node.TEXT_NODE)
|
|
|
|
|
})
|
|
|
|
|
const currentIndex = siblings.indexOf(this.targetNode)
|
|
|
|
|
|
|
|
|
|
if (key === "ArrowUp" && currentIndex > 0) {
|
|
|
|
|
const prevSibling = siblings[currentIndex - 1]
|
2025-01-15 19:00:31 +08:00
|
|
|
|
const index = Math.max(0, Math.min(prevSibling.textContent.length, this.insertIndex))
|
2025-01-15 16:35:20 +08:00
|
|
|
|
this.setTarget(prevSibling, index) // 光标在上一个兄弟元素的起始位置
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key === "ArrowDown" && currentIndex >= 0 && currentIndex < siblings.length - 1) {
|
|
|
|
|
const nextSibling = siblings[currentIndex + 1]
|
2025-01-15 19:00:31 +08:00
|
|
|
|
const index = Math.max(0, Math.min(nextSibling.textContent.length, this.insertIndex))
|
2025-01-15 16:35:20 +08:00
|
|
|
|
this.setTarget(nextSibling, index) // 光标在下一个兄弟元素的起始位置
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key === "ArrowLeft" && this.insertIndex > 0) {
|
|
|
|
|
this.insertIndex = Math.max(0, Math.min(this.targetNode.textContent.length, this.insertIndex - 1))
|
|
|
|
|
this.updateRange()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (key === "ArrowRight" && this.insertIndex < this.targetNode.textContent.length) {
|
|
|
|
|
this.insertIndex = Math.max(0, Math.min(this.targetNode.textContent.length, this.insertIndex + 1))
|
|
|
|
|
this.updateRange()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default { cursors, Cursor }
|