contenteditable div调用focus()后光标为何定位至开头?
问题描述
开发基于PHP的书籍写作网站,点击「Chapter Title」按钮触发addChapter()函数,AJAX请求完成后向带contenteditable属性的#content div追加章节标题内容,预期光标定位到div内容末尾,但实际光标移至div开头。
相关信息
- 浏览器:Chrome 107.0.5304.62(64位)
- 控制台无任何错误提示
- 手动将光标移至末尾后添加第二个章节,光标会定位到最新追加内容的开头
- 需求:尽量避免使用textarea,防止PHP处理时产生多余空白
解决方案
直接调用focus()只能让元素获得焦点,无法自动将光标定位到内容末尾。需要手动创建文本选区,强制将光标移到contenteditable元素的最后位置。
1. 新增光标定位函数
添加一个通用函数,专门处理contenteditable元素的光标末尾定位:
function placeCursorAtEnd(el) { el.focus(); const range = document.createRange(); const selection = window.getSelection(); range.selectNodeContents(el); range.collapse(false); // 折叠选区到内容末尾 selection.removeAllRanges(); selection.addRange(range); }
2. 修改原addChapter()函数
把原来的div.focus()替换为调用上述函数:
function addChapter() { let chapter = prompt("New Chapter Name?"); if (chapter != null) { $.get("editor.php?newchapter=" + chapter, function (data, status) { $("#toc_base").html("<li>" + chapter + "</li>"); $("#content").append("[b]" + chapter + "[/b]\n\n"); var div = document.getElementById('content'); placeCursorAtEnd(div); // 替换原有的div.focus() }); } }
原理说明
document.createRange()创建范围对象,用于选中元素内容range.selectNodeContents(el)选中目标元素的全部内容range.collapse(false)将选区折叠到末尾(传true会折叠到开头)- 通过
window.getSelection()获取当前选区,移除原有选区后添加新的范围,就能强制光标定位到内容末尾
如果遇到AJAX后DOM更新延迟导致函数不生效的情况,可以给定位函数加个微小延迟:
setTimeout(() => placeCursorAtEnd(div), 10);
内容的提问来源于stack exchange,提问作者jpgerb
相关产品推荐
相关产品推荐

