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 }