cooperation/cursor.js
2025-01-15 19:00:31 +08:00

120 lines
4.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.

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]
const index = Math.max(0, Math.min(prevSibling.textContent.length, this.insertIndex))
this.setTarget(prevSibling, index) // 光标在上一个兄弟元素的起始位置
return
}
if (key === "ArrowDown" && currentIndex >= 0 && currentIndex < siblings.length - 1) {
const nextSibling = siblings[currentIndex + 1]
const index = Math.max(0, Math.min(nextSibling.textContent.length, this.insertIndex))
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 }