cooperation/cursor.js

122 lines
4.0 KiB
JavaScript
Raw Normal View History

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