求Summer-Note编辑器自定义查找下一个与替换按钮的JS代码
解决Summer-Note查找下一个与替换功能的完整方案
我之前帮不少开发者搞定过Summer-Note的自定义工具栏功能,你的需求核心是要维护查找状态,逐个遍历匹配项并支持替换当前选中的匹配内容,下面是可直接运行的实现代码和关键逻辑说明:
1. 基础配置与工具栏自定义
首先确保你已经引入了Summer-Note的CSS和JS依赖,然后在编辑器初始化时,把自定义的「查找下一个」和「替换」按钮加入工具栏:
<!-- 引入Summer-Note依赖 --> <link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote-bs4.min.js"></script> <!-- 编辑器容器 --> <div id="summernote"></div>
// 初始化Summer-Note $(document).ready(function() { // 维护查找状态的变量(封装在闭包内避免全局污染) let currentSearchTerm = ''; let matches = []; let currentMatchIndex = -1; const $editor = $('#summernote'); $editor.summernote({ height: 300, toolbar: [ ['style', ['style']], ['font', ['bold', 'underline', 'clear']], ['color', ['color']], ['para', ['ul', 'ol', 'paragraph']], ['custom', ['findNext', 'replace']], // 新增自定义工具栏组 ['view', ['fullscreen', 'codeview', 'help']] ], // 注册自定义按钮 buttons: { findNext: function(context) { const button = context.ui.button({ contents: '<i class="fa fa-search"></i> 查找下一个', tooltip: '查找下一个匹配项', click: function() { handleFindNext(context); } }); return button.render(); }, replace: function(context) { const button = context.ui.button({ contents: '<i class="fa fa-exchange"></i> 替换', tooltip: '替换当前匹配项', click: function() { const replaceText = prompt('请输入替换内容:'); if (replaceText !== null) { handleReplaceCurrent(context, replaceText); } } }); return button.render(); } } }); // --- 核心功能函数 --- // 获取所有匹配项的位置信息 function findMatches(context, searchTerm) { const $editable = context.layoutInfo.editable; const content = $editable.text(); // 转义正则特殊字符,启用不区分大小写匹配 const regex = new RegExp(searchTerm.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi'); const matchList = []; let match; while ((match = regex.exec(content)) !== null) { matchList.push({ start: match.index, end: match.index + match[0].length }); // 处理空匹配的无限循环问题 if (match[0].length === 0) regex.lastIndex++; } return matchList; } // 选中指定位置的匹配项 function selectMatch(context, match) { const $editable = context.layoutInfo.editable[0]; const range = document.createRange(); const selection = window.getSelection(); // 定位到目标文本节点(适配简单HTML结构) let textNode = $editable.firstChild; let currentOffset = 0; while (textNode && currentOffset + textNode.length < match.start) { currentOffset += textNode.length; textNode = textNode.nextSibling; } if (textNode) { range.setStart(textNode, match.start - currentOffset); range.setEnd(textNode, match.end - currentOffset); selection.removeAllRanges(); selection.addRange(range); // 平滑滚动到选中区域 $editable.scrollIntoView({ behavior: 'smooth', block: 'center' }); } } // 查找下一个匹配项 function handleFindNext(context) { const searchTerm = prompt('请输入要查找的内容:'); if (searchTerm === null) return; // 切换新关键词时重置查找状态 if (searchTerm !== currentSearchTerm) { currentSearchTerm = searchTerm; matches = findMatches(context, searchTerm); currentMatchIndex = -1; } if (matches.length === 0) { alert('未找到匹配内容'); return; } // 循环遍历匹配项(到末尾后回到第一个) currentMatchIndex = (currentMatchIndex + 1) % matches.length; selectMatch(context, matches[currentMatchIndex]); } // 替换当前匹配项 function handleReplaceCurrent(context, replaceText) { if (currentMatchIndex === -1 || matches.length === 0) { alert('请先执行查找操作'); return; } const $editable = context.layoutInfo.editable; const content = $editable.text(); // 替换当前匹配的内容 const newContent = content.substring(0, matches[currentMatchIndex].start) + replaceText + content.substring(matches[currentMatchIndex].end); // 更新编辑器内容 $editable.text(newContent); // 重新扫描匹配项(内容已修改) matches = findMatches(context, currentSearchTerm); // 定位到下一个有效匹配项 if (matches.length > 0) { currentMatchIndex = Math.min(currentMatchIndex, matches.length - 1); selectMatch(context, matches[currentMatchIndex]); } else { currentMatchIndex = -1; alert('已无匹配内容'); } } });
关键逻辑说明
- 状态管理:通过
currentSearchTerm、matches、currentMatchIndex三个变量,记录当前查找关键词、所有匹配项位置、当前选中匹配项的索引,这是实现「查找下一个」「替换当前」的核心。 - 匹配定位:使用
document.createRange()和window.getSelection()API,精准定位编辑器内的匹配文本并高亮选中。 - 替换后更新:替换完成后重新扫描内容生成新的匹配列表,确保后续查找的准确性。
- 正则安全处理:对用户输入的关键词进行正则特殊字符转义,避免因输入特殊字符导致正则解析错误。
你可以直接复制这段代码到项目中测试,也可以根据需求调整按钮图标、提示文本或适配复杂HTML结构。
内容的提问来源于stack exchange,提问作者keerti




