动态创建Summernote富文本编辑器后格式操作光标跳转问题
动态创建Summernote编辑器光标跳转问题解决
问题现象
已引入JQuery和Bootstrap,静态HTML中使用Summernote富文本编辑器一切正常,但通过JavaScript动态创建多个编辑器后,初始化及保存功能正常,执行加粗、斜体或修改字体颜色等格式操作时,光标会跳转到行首,无法正常选中文本修改。
相关代码
创建编辑器的函数
function createRTE(lang, field_name = 'description', required = true) { const rte_div = document.createElement('div'); const rte = document.createElement('div'); rte.setAttribute('name', 'content[' + global_counter + '][' + field_name +']['+lang+']'); rte.setAttribute('class', 'summernote'); rte.setAttribute('data-textarea', 'rte_' + global_counter + '_' + lang); const rte_textarea = document.createElement('textarea'); rte_textarea.setAttribute('name', 'content[' + global_counter + '][' + field_name +']['+lang+']'); rte_textarea.setAttribute('id', 'rte_' + global_counter + '_' + lang); rte_textarea.setAttribute('hidden', 'true'); rte_div.appendChild(rte_textarea); rte_div.appendChild(rte); return rte_div; }
初始化编辑器的函数
function initSummernote(selector = '.summernote') { if (!$.fn.summernote) { return; } const elems = document.querySelectorAll(selector); for (const elem of elems) { $(elem).summernote({ dialogsFade: true, dialogsInBody: true, height: elem.dataset.height ?? 300, fontNames: [], maximumImageFileSize: 1024 * 1024, tableClassName: 'table table-hover table-bordered', toolbar: [ ['actions', ['undo', 'redo']], ['style', ['style']], ['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph', 'hr']], ['table', ['table']], ['insert', ['link', 'picture', 'video']], ['view', ['fullscreen', 'codeview', 'help']] ], callbacks: { onChange(contents) { if (elem.dataset.textarea) { document.getElementById(elem.dataset.textarea).value = $(elem).summernote('isEmpty') ? '' : contents.trim(); } } } }); } }
问题原因
核心问题出在onChange回调中实时同步内容到隐藏textarea的操作:每次编辑器内容变化(包括格式修改)都会直接更新textarea的值,这个操作会干扰Summernote内部的光标位置管理,导致格式操作后光标跳转到行首。
另外,初始化函数中遍历所有.summernote元素,若重复调用会对已初始化的编辑器重复执行初始化,也可能引发异常。
解决方案
方案1:修改内容同步时机,避免实时同步
将onChange的实时同步改为表单提交时统一同步,彻底避免光标干扰:
- 移除
onChange回调,调整初始化函数:
function initSummernote(selector = '.summernote') { if (!$.fn.summernote) { return; } // 只初始化未被初始化过的元素,避免重复初始化 const elems = document.querySelectorAll(`${selector}:not(.note-editor)`); for (const elem of elems) { $(elem).summernote({ dialogsFade: true, dialogsInBody: true, height: elem.dataset.height ?? 300, fontNames: [], maximumImageFileSize: 1024 * 1024, tableClassName: 'table table-hover table-bordered', toolbar: [ ['actions', ['undo', 'redo']], ['style', ['style']], ['font', ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'clear']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph', 'hr']], ['table', ['table']], ['insert', ['link', 'picture', 'video']], ['view', ['fullscreen', 'codeview', 'help']] ] // 移除onChange回调 }); } }
- 添加表单提交事件处理,统一同步内容:
// 替换为你的表单选择器 document.querySelector('form').addEventListener('submit', function(e) { $('.summernote').each(function() { const textareaId = $(this).data('textarea'); if (textareaId) { const contents = $(this).summernote('isEmpty') ? '' : $(this).summernote('code').trim(); document.getElementById(textareaId).value = contents; } }); });
方案2:保留实时同步但优化光标处理
如果必须实时同步,可通过保存/恢复光标位置解决:
callbacks: { onChange(contents) { if (elem.dataset.textarea) { // 保存当前光标位置 const range = $(elem).summernote('createRange'); // 延迟执行同步,避免干扰格式操作的光标处理 setTimeout(() => { document.getElementById(elem.dataset.textarea).value = $(elem).summernote('isEmpty') ? '' : contents.trim(); // 恢复光标位置 $(elem).summernote('restoreRange', range); }, 10); } } }
额外优化:避免重复初始化
修改初始化函数的选择器,只针对未初始化的元素(Summernote初始化后会添加.note-editor类),防止重复初始化引发异常:
const elems = document.querySelectorAll(`${selector}:not(.note-editor)`);
问题截图
- 选中文本并点击格式按钮:

- 点击格式按钮后光标跳转至行首:

内容的提问来源于stack exchange,提问作者Leon Kardaš
相关产品推荐
相关产品推荐

