最近在做一个边输入边编辑的前端功能,就是用户选中div里面的内容之后,需要给加个高亮的效果,这个简单,给选中的内容直接嵌套一个带border的div就行了,本来这块也没啥,真正头大的是需要给后台发送选中内容在整个串里的开始和结束下标,当时搜了一大堆.说用什么anchorOffset和focusOffset,
先说一下,这两个属性是没有问题的,确确实实是可以获取到div选中内容在选中对象里的开始和结束下标,但是呢,我现在是最外部有一个大的div,然后里面高亮后会加入子div,这样的话,选中内容只会是高亮对象的那个下标而不是相对于最外部那个的div的下标,
吹解决办法了:
这个方法也是百度给的,直接可以把选中的内容替换成你想要的结果,我的高亮就是这么实现的,把选中的内容套进带border的div在替换就行了,
这块当时真的是挣扎了好久好久,最后还是想了一个小法子,
标记查找
实现原理:先把选中的内容用特殊标记符包裹起来替换进去,然后拿到最外部整串的text()进行遍历,找到标记符包裹的内容记录下开始和结束下标,然后删除之前替换的带标记的内容,重新把带高亮的在替换进去就行了
//输入框选中事件
$("#add-input-journal").click(function() {
const sel = window.getSelection();
var checkStr = sel.toString();
//判断是否有选中内容
if(null != checkStr && checkStr.length >= 1) {
var flag = obtainId(sel);//判断是否存在Id(避免已高亮的继续选择子元素高亮)
if(flag == true) {
alert("对不起,不能包含已选择过的!");
return;
}
if(sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range2 = sel.getRangeAt(0);
range.deleteContents();
range2.deleteContents();
randomId = "tid" + createRandom(randomId);//随机生成高亮div的ID
var el = document.createElement("div");
var newstr = '<div id="' + randomId + '" class="forbidcheck" contenteditable="false" style="box-shadow: 0 0 2px 2px #BBDDF8;padding: 4px 3px 2px; display:inline;border-radius:8px">#@&' + checkStr + '#@&</div>';//添加特殊标识符""************#@&**************""
el.innerHTML = newstr;
tempStr = newstr;
var frag = document.createDocumentFragment(),
node, lastNode;
while((node = el.firstChild)) {
lastNode = frag.appendChild(node);
}
//先添加后删除再获取开始结束下标
range.insertNode(frag);//这块是替换带特殊标识符的div
getIndex($("#add-input-journal").text());//获取选中内容在整串的开始和结束下标
range.deleteContents();//获取完了,删了这段
var el2 = document.createElement("div");
var newstr2 = '<div id="' + randomId + '" class="forbidcheck" contenteditable="false"
style="box-shadow: 0 0 2px 2px #BBDDF8;padding: 4px 3px 2px; display:inline;border-radius:8px">' + checkStr + '</div>';
el2.innerHTML = newstr2;
//添加鼠标事件
var frag2 = document.createDocumentFragment(),
node2, lastNode2;
while((node2 = el2.firstChild)) {
lastNode2 = frag2.appendChild(node2);
}
//最后替换没有标识的字符串
range2.insertNode(frag2);//这才是真正的替换内容
getStr($("#add-input-journal").text());
// Preserve the selection
if(lastNode) {//注:必须加这句!!!没有这句,高亮后点击高亮div直接显示选中内容为上次选中内容,BUG!!!加上后高亮点击显示选中内容为'',感觉类似于移除焦点,
range = range.cloneRange();
range.setStartAfter(lastNode);
range.collapse(true);
sel.removeAllRanges();
sel.addRange(range);
}
}
}
return false; //关键是这里,阻止冒泡
});
function getIndex(str) {
for(var i = 0; i < str.length; i++) {//直接找下标喽!!!
if(str.charAt(i) == '#' && str.charAt(i + 1) == '@' && str.charAt(i + 2) == '&'){
console.log(i+" i");
if(start != ""){
end = i
}else{
start = i;
}
}
}
}
var newstr = '<div id="' + randomId + '" class="forbidcheck" contenteditable="false" style="box-shadow: 0 0 2px 2px #BBDDF8;padding: 4px 3px 2px; display:inline;border-radius:8px">#@&' + checkStr + '#@&</div>';
这里面的**""#@&""**就是我加的标识符了,相信一般没有这么特殊的,当然了,这个可以自己定义用啥标记都可以,哦哦,那个start的值没有问题,end需要 -3 ,目前我实现的就是不停的给选中的高亮,有很多的子div也没关系啊/开心
,