基于ueditor编辑器的功能开发之重写ueditor的查找和替换功能,支持滚动定位
百度编辑器的查找和替换无法随着页面滚动定位,找到searchreplace.js,重写里面的方法
效果展示:
20250421173735
思路:
找到查找和替换的输入框,发现id名分别为findtxt和findtxt1,分别绑定change事件,并定义两套变量,分别为currentIndex 、matches和replacecurrentIndex、replacematches用于存储当前滚动到的数组位置和查找到的文本的位置的数组列表
点击下一个上一个按钮的的时候注释原来的代码,改为调用我们自己写的方法scrollToMatch,参数传递当前要定位的数组索引和类型(查找或者替换),代码如下
/*** Created with JetBrains PhpStorm.* User: xuheng* Date: 12-9-26* Time: 下午12:29* To change this template use File | Settings | File Templates.*///清空上次查选的痕迹
editor.firstForSR = 0;
editor.currentRangeForSR = null;
//给tab注册切换事件
/*** tab点击处理事件* @param tabHeads* @param tabBodys* @param obj*/
//相关搜索变量
//当前查找的变量
let currentIndex = -1;
let matches = [];
// 当前替换的变量
let replacecurrentIndex = -1
let replacematches = []
// let highlightSpan = document.createElement('span');
// highlightSpan.style.backgroundColor = '#ff0000';
// highlightSpan.style.color = '#ffffff';
// let execFlag = false;
function clickHandler( tabHeads,tabBodys,obj ) {//head样式更改for ( var k = 0, len = tabHeads.length; k < len; k++ ) {tabHeads[k].className = "";}obj.className = "focus";//body显隐var tabSrc = obj.getAttribute( "tabSrc" );for ( var j = 0, length = tabBodys.length; j < length; j++ ) {var body = tabBodys[j],id = body.getAttribute( "id" );if ( id != tabSrc ) {body.style.zIndex = 1;} else {body.style.zIndex = 200;}}}/*** TAB切换* @param tabParentId tab的父节点ID或者对象本身*/
function switchTab( tabParentId ) {var tabElements = $G( tabParentId ).children,tabHeads = tabElements[0].children,tabBodys = tabElements[1].children;for ( var i = 0, length = tabHeads.length; i < length; i++ ) {var head = tabHeads[i];if ( head.className === "focus" )clickHandler(tabHeads,tabBodys, head );head.onclick = function () {clickHandler(tabHeads,tabBodys,this);}}
}
$G('searchtab').onmousedown = function(){$G('search-msg').innerHTML = '';$G('replace-msg').innerHTML = ''
}
//是否区分大小写
function getMatchCase(id) {return $G(id).checked ? true : false;
}
// 给输入框绑定change时间,用于变量初始化
$G('findtxt').onchange =function(e){console.log(e,'input输入框时间是否改变')currentIndex = -1; //当前matches = [];searchText('findtxt')
}
// 给替换绑定change事件
$G('findtxt1').onchange =function(e){console.log(e,'替换是否改变')replacecurrentIndex = -1; //当前replacematches = [];searchText('findtxt1')
}
//查找
$G("nextFindBtn").onclick = function (txt, dir, mcase) {var findtxt = $G("findtxt").value, obj;if (!findtxt) {return false;}if (matches.length === 0) return;currentIndex = (currentIndex + 1) % matches.length;scrollToMatch(currentIndex,'findtxt');// 自定义实现查找过程// this.searchText()// obj = {// searchStr:findtxt,// dir:1,// casesensitive:getMatchCase("matchCase")// };// if (!frCommond(obj)) {// var bk = editor.selection.getRange().createBookmark();// $G('search-msg').innerHTML = lang.getEnd;// editor.selection.getRange().moveToBookmark(bk).select();// }
};
$G("nextReplaceBtn").onclick = function (txt, dir, mcase) {var findtxt = $G("findtxt1").value, obj;if (!findtxt) {return false;}// obj = {// searchStr:findtxt,// dir:1,// casesensitive:getMatchCase("matchCase1")// };// frCommond(obj);if (replacecurrentIndex.length === 0) return;replacecurrentIndex = (replacecurrentIndex + 1) % replacematches.length;scrollToMatch(replacecurrentIndex,'findtxt1');
};
$G("preFindBtn").onclick = function (txt, dir, mcase) {var findtxt = $G("findtxt").value, obj;if (!findtxt) {return false;}// obj = {// searchStr:findtxt,// dir:-1,// casesensitive:getMatchCase("matchCase")// };// if (!frCommond(obj)) {// $G('search-msg').innerHTML = lang.getStart;// }if (matches.length === 0) return;currentIndex = (currentIndex - 1 + matches.length) % matches.length;scrollToMatch(currentIndex,'findtxt');
};
$G("preReplaceBtn").onclick = function (txt, dir, mcase) {var findtxt = $G("findtxt1").value, obj;if (!findtxt) {return false;}// obj = {// searchStr:findtxt,// dir:-1,// casesensitive:getMatchCase("matchCase1")// };// frCommond(obj);if (replacecurrentIndex.length === 0) return;replacecurrentIndex = (replacecurrentIndex - 1 + replacematches.length) % replacematches.length;scrollToMatch(replacecurrentIndex,'findtxt1');
};
//替换
$G("repalceBtn").onclick = function () {var findtxt = $G("findtxt1").value.replace(/^\s|\s$/g, ""), obj,replacetxt = $G("replacetxt").value.replace(/^\s|\s$/g, "");if (!findtxt) {return false;}if (findtxt == replacetxt || (!getMatchCase("matchCase1") && findtxt.toLowerCase() == replacetxt.toLowerCase())) {return false;}obj = {searchStr:findtxt,dir:1,casesensitive:getMatchCase("matchCase1"),replaceStr:replacetxt};frCommond(obj);
};
//全部替换
$G("repalceAllBtn").onclick = function () {var findtxt = $G("findtxt1").value.replace(/^\s|\s$/g, ""), obj,replacetxt = $G("replacetxt").value.replace(/^\s|\s$/g, "");if (!findtxt) {return false;}if (findtxt == replacetxt || (!getMatchCase("matchCase1") && findtxt.toLowerCase() == replacetxt.toLowerCase())) {return false;}obj = {searchStr:findtxt,casesensitive:getMatchCase("matchCase1"),replaceStr:replacetxt,all:true};var num = frCommond(obj);if (num) {$G('replace-msg').innerHTML = lang.countMsg.replace("{#count}", num);}
};
//执行
var frCommond = function (obj) {return editor.execCommand("searchreplace", obj);
};
function searchText(str) {let searchValue = $G(`${str}`).valueif (!searchValue) return;//获取编辑器内容//获取编辑器iframe文档对象const iframeDoc = editor.iframe.contentDocument;const body = iframeDoc.body;const textNodes = getTextNodes(body);//查找所有匹配项if(str == 'findtxt1'){replacematches = []} else {matches = []}textNodes.forEach(node => {const nodeText = node.nodeValue;const regex = new RegExp(`(${searchValue})`, 'gi');let match;while ((match = regex.exec(nodeText)) !== null) {if(str == 'findtxt1'){replacematches.push({node,offset: match.index,length: match[0].length})} else {matches.push({node,offset: match.index,length: match[0].length})}}});console.log(matches,replacematches,'matches')
}
//获取所有文本节点
function getTextNodes(node) {const textNodes = [];if (node.nodeType === Node.TEXT_NODE) {textNodes.push(node);} else {const children = node.childNodes;for (let i = 0; i < children.length; i++) {textNodes.push(...getTextNodes(children[i]));}}return textNodes;
}
//定位到指定匹配项
function scrollToMatch(index,str) {let flagif(str =='findtxt1'){if (replacematches.length === 0 || replacecurrentIndex < 0 || replacecurrentIndex >= replacematches.length){flag = true}} else if(str =='findtxt'){if (matches.length === 0 || currentIndex < 0 || currentIndex >= matches.length){flag = true}}if(flag) returnlet iframeDoc = editor.iframe.contentDocument;let selection = iframeDoc.getSelection();selection.removeAllRanges();let match = str == 'findtxt1' ?replacematches[index]:matches[index];let range = document.createRange();range.setStart(match.node, match.offset);range.setEnd(match.node, match.offset + match.length);selection.addRange(range);// range.surroundContents(highlightSpan);// editor.fireEvent('selectionchange');let rect = range.getBoundingClientRect();// let iframeWindow = editor.iframe.contentWindow;// let body = iframeWindow.document.querySelector('body');//计算滚动位置let scrollTop = rect.top + editor.document.documentElement.scrollTop - 30;editor.document.documentElement.scrollTo({top: scrollTop,behavior: "smooth"});
}
switchTab("searchtab");