光标移动
This commit is contained in:
parent
753f40ab29
commit
b36dc6ed10
121
cursor.js
Normal file
121
cursor.js
Normal file
@ -0,0 +1,121 @@
|
||||
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 }
|
156
markdown.js
156
markdown.js
@ -1,4 +1,5 @@
|
||||
import { Marked } from "marked"
|
||||
import { cursors, Cursor } from "./cursor"
|
||||
|
||||
// 示例 Markdown 文本
|
||||
const markdown = `
|
||||
@ -17,125 +18,6 @@ const markdown = `
|
||||
const marked = new Marked()
|
||||
const tokens = marked.lexer(markdown)
|
||||
|
||||
// 光标
|
||||
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", // 初始隐藏
|
||||
})
|
||||
return cursorElement
|
||||
}
|
||||
|
||||
// 设置目标文本节点和插入位置
|
||||
setTarget(node, index) {
|
||||
this.targetNode = node
|
||||
this.insertIndex = index
|
||||
this.updateRange()
|
||||
}
|
||||
|
||||
// 更新插入位置索引
|
||||
updateInsertIndex(offset) {
|
||||
this.insertIndex = Math.max(0, Math.min(this.targetNode.textContent.length, this.insertIndex + offset))
|
||||
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()
|
||||
}
|
||||
|
||||
// 获取目标节点的上下兄弟节点
|
||||
getSiblingNodes() {
|
||||
const parent = this.targetNode.parentNode
|
||||
const siblings = Array.from(parent.childNodes).filter(
|
||||
(node) => node !== this.targetNode && node.nodeType === Node.TEXT_NODE
|
||||
)
|
||||
return siblings
|
||||
}
|
||||
|
||||
// 根据当前光标位置移动到上下兄弟节点
|
||||
moveUp() {
|
||||
console.log('根据当前光标位置移动到上下兄弟节点')
|
||||
const siblings = this.getSiblingNodes()
|
||||
const currentIndex = siblings.indexOf(this.targetNode)
|
||||
if (currentIndex > 0) {
|
||||
const prevSibling = siblings[currentIndex - 1]
|
||||
this.setTarget(prevSibling, prevSibling.textContent.length)
|
||||
}
|
||||
}
|
||||
|
||||
moveDown() {
|
||||
const siblings = this.getSiblingNodes()
|
||||
const currentIndex = siblings.indexOf(this.targetNode)
|
||||
if (currentIndex < siblings.length - 1) {
|
||||
const nextSibling = siblings[currentIndex + 1]
|
||||
this.setTarget(nextSibling, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 光标集合,存储所有光标
|
||||
const cursors = []
|
||||
let defaultCursor = new Cursor() // 初始创建默认光标
|
||||
cursors.push(defaultCursor) // 将默认光标添加到光标集合
|
||||
|
||||
// 创建 textarea 接受输入
|
||||
const textarea = document.createElement("textarea")
|
||||
Object.assign(textarea.style, {
|
||||
@ -174,26 +56,10 @@ textarea.oninput = () => {
|
||||
|
||||
// 处理方向键移动插入点
|
||||
textarea.onkeydown = (event) => {
|
||||
console.log(event.key)
|
||||
|
||||
if (!cursors.length) return
|
||||
|
||||
cursors.forEach(cursor => {
|
||||
if (!cursor.targetNode || cursor.insertIndex === null) return
|
||||
|
||||
if (event.key === "ArrowLeft") {
|
||||
cursor.updateInsertIndex(-1)
|
||||
} else if (event.key === "ArrowRight") {
|
||||
cursor.updateInsertIndex(1)
|
||||
} else if (event.key === "ArrowUp") {
|
||||
cursor.moveUp()
|
||||
} else if (event.key === "ArrowDown") {
|
||||
cursor.moveDown()
|
||||
}
|
||||
cursors.filter(cursor => cursor.targetNode && cursor.insertIndex !== null).forEach(cursor => {
|
||||
cursor.move(event.key)
|
||||
updateCursors()
|
||||
})
|
||||
|
||||
// 更新光标位置
|
||||
updateCursors()
|
||||
}
|
||||
|
||||
// 更新所有光标的位置
|
||||
@ -260,19 +126,19 @@ element.onclick = (event) => {
|
||||
// 设置光标的目标节点和插入位置
|
||||
cursors.forEach(cursor => cursor.setTarget(targetNode, insertIndex))
|
||||
|
||||
// 如果是点击多个光标的情况,增加新光标
|
||||
if (event.ctrlKey || !cursors.length) {
|
||||
const newCursor = new Cursor(targetNode, insertIndex)
|
||||
cursors.push(newCursor)
|
||||
console.log("新增光标")
|
||||
}
|
||||
|
||||
// 更新光标位置
|
||||
updateCursors()
|
||||
|
||||
// 聚焦输入框
|
||||
textarea.value = ""
|
||||
textarea.focus()
|
||||
|
||||
// 如果是点击多个光标的情况,增加新光标
|
||||
if (event.ctrlKey) {
|
||||
const newCursor = new Cursor(targetNode, insertIndex)
|
||||
cursors.push(newCursor)
|
||||
console.log("新增光标")
|
||||
}
|
||||
}
|
||||
|
||||
// 按删除键移除光标
|
||||
|
Loading…
Reference in New Issue
Block a user