120 lines
4.0 KiB
JavaScript
120 lines
4.0 KiB
JavaScript
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 }
|