<!DOCTYPE html>
<html>
<head>
<title>ContentEditable Cursor Demo</title>
<style>
#editor {
border: 1px solid #ccc;
padding: 10px;
margin: 10px;
min-height: 100px;
}
</style>
</head>
<body>
<div id="editor" contenteditable="true"><span>poipiopiop</span><span>ljkljkljkljkl</span></div>
<button onclick="replaceContent()">替换内容并保持光标</button>
<script>
const editor = document.getElementById('editor');
function getGlobalOffset() {
const selection = window.getSelection();
if (!selection.rangeCount) return 0;
const range = selection.getRangeAt(0);
let offset = 0;
const nodeStack = [editor];
let found = false;
while (nodeStack.length > 0 && !found) {
const node = nodeStack.pop();
if (node.nodeType === Node.TEXT_NODE) {
if (node === range.startContainer) {
offset += range.startOffset;
found = true;
} else {
offset += node.textContent.length;
}
} else {
for (let i = node.childNodes.length - 1; i >= 0; i--) {
nodeStack.push(node.childNodes[i]);
}
}
}
return offset;
}
function setGlobalOffset(targetOffset) {
let currentOffset = 0;
let targetNode = editor;
let targetNodeOffset = 0;
const walker = document.createTreeWalker(
editor,
NodeFilter.SHOW_TEXT,
null,
false
);
let node;
while ((node = walker.nextNode())) {
const nodeLength = node.textContent.length;
if (currentOffset + nodeLength > targetOffset) {
targetNode = node;
targetNodeOffset = targetOffset - currentOffset;
break;
}
currentOffset += nodeLength;
}
if (!targetNode || targetNode.nodeType !== Node.TEXT_NODE) {
const allChildren = editor.childNodes;
targetNode = editor;
targetNodeOffset = allChildren.length;
}
const range = document.createRange();
range.setStart(targetNode, targetNodeOffset);
range.collapse(true);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
function replaceContent() {
const originalOffset = getGlobalOffset();
const newText = `<span>asdfasdf</span><span>zxcvzxcvzxcvsadf</span>`;
editor.innerHTML = newText;
let newContentLength = 0;
const walker = document.createTreeWalker(
editor,
NodeFilter.SHOW_TEXT,
null,
false
);
let node;
while ((node = walker.nextNode())) {
newContentLength += node.textContent.length;
}
const adjustedOffset = Math.min(originalOffset, newContentLength);
setGlobalOffset(adjustedOffset);
editor.focus();
}
</script>
</body>
</html>