上次分享了全局input增加敏感词检测的功能,有人私信我:如何解决光标漂移问题?
我们每次替换完文本,光标总是会飘到文本的最前面,而且不仅是input文本框,富文本编辑器(可编辑div)也有这个问题,如果直接用innerHTML方法直接替换内容的话,也会出现光标漂移的问题,如何解决呢?
我们先要搞清楚光标是个啥东西,其实光标这玩意本身就是一个js对象,其本身封装了一些属性和方法。
index.html:
//================================过滤敏感词===================================================//
document.addEventListener('input', debounce(handleWords, 800));
function handleWords(e) {
console.log('currentPos>>>', getCursorPos(e.target));
let words = e.target.value;
let wordType = '';
if(e.target.nodeName === 'INPUT' && (!e.target.getAttribute('type') || e.target.getAttribute('type')=== 'text')) {
console.log('text标签');
wordType = 'input';
}
if (words && e.target.nodeName === 'TEXTAREA') {
wordType = 'textarea';
}
if (!words && e.target.nodeName === 'DIV') {
//可编辑文本框,包括富文本
words = e.target.innerHTML;
wordType = 'div';
}
//查询敏感词
if (words && wordType) {
//空白字符不做检测
if(e.target.nodeName === 'DIV' && !e.target.innerText.replace(/\s+/g,'')){
return false;
}
fetch(`/checkSensitiveWords`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: `words=${words}&wordtype=${wordType}`
}).then(response => response.text()).then(res => {
if (res) {
if (wordType === 'input') {
e.target.value = res;
setCursorPos(e.target, getCursorPos(e.target));//设置光标位置
} else if (wordType === 'div') {
pasteHtmlAtCaret(e.target, res);//不可使用e.target.innerHTML,会有光标漂移问题
}
e.target.dispatchEvent(new Event('input'));//更新ngModel视图
}
})
}
}
function pasteHtmlAtCaret(el, html, selectPastedContent) {//参数1为要插入的html //参数2为boolean 是否选中插入的html 默认为false
var sel, range;
if (window.getSelection) {
// IE9 and non-IE
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
// Range.createContextualFragment() would be useful here but is
// only relatively recently standardized and is not supported in
// some browsers (IE9, for one)
el.innerHTML = html;
var frag = document.createDocumentFragment(), node, lastNode;
while ((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
var firstNode = frag.firstChild;
range.insertNode(frag);
// Preserve the selection
if (lastNode) {
range = range.cloneRange();
range.setStartAfter(lastNode);
if (selectPastedContent) {
range.setStartBefore(firstNode);
} else {
range.collapse(true);
}
sel.removeAllRanges();
sel.addRange(range);
}
}
} else if ((sel = document.selection) && sel.type != "Control") {
// IE < 9
var originalRange = sel.createRange();
originalRange.collapse(true);
sel.createRange().pasteHTML(html);
if (selectPastedContent) {
range = sel.createRange();
range.setEndPoint("StartToStart", originalRange);
range.select();
}
}
}
//获取光标位置,仅对input有效
function getCursorPos(input) {
var pos = 0;
// IE Support
if (document.selection) {
input.focus();
var sel = document.selection.createRange();
var selLen = document.selection.createRange().text.length;
sel.moveStart('character', -input.value.length);
pos = sel.text.length - selLen;
}
// Firefox support
else if (input.selectionStart || input.selectionStart == '0')
pos = input.selectionStart;
return pos;
}
//设置光标位置,仅对input有效
function setCursorPos(obj, pos) {
if (obj.setSelectionRange) {//Firefox/Safari/Chrome/Opera
obj.focus();
obj.setSelectionRange(pos, pos);
} else if (obj.createTextRange) { // IE
var range = obj.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
}
//防抖
function debounce(fn, delay) {
var timer = null;
return function (...args) {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, args)
}, delay)
}
}
后台代码:
@ApiOperation({ summary: "过滤敏感词", description: "过滤敏感关键词和特殊字符" })
@Post('checkSensitiveWords')
async checkSensitiveWords(@Body() params): Promise<any> {
let words = params.words;
let wordType = params.wordtype;
let newWords = words;
if (words) {
let sensitiveWords = sensitiveWordsFunc();
if (Array.isArray(sensitiveWords)) {
sensitiveWords.forEach(item => {
let stripSpecWords = words;
if(wordType === 'input') {
stripSpecWords = words.replace(/\s+/g, "");//获取字符串信息,清除所有空格
stripSpecWords = stripSpecWords.replace(/[\-\_\,\!\|\~\`\(\)\#\$\%\^\&\*\{\}\:\;\"\L\<\>\?]/g, '');
}
let reg = new RegExp(item,"ig");
if (item && reg.test(stripSpecWords)) {
newWords = stripSpecWords.replace(reg, '囗'.repeat(item.length));
}
});
console.log('newords>>>', newWords);
return newWords;
}
}
return newWords;
}
网友评论