JS获取嵌套div选中内容的开始和结束下标问题

本文介绍了一种前端技术,用于实现用户在div元素内选中文本后的高亮效果,并通过特殊标记符记录选中内容在整个文本串中的起始与结束位置,解决了在嵌套div结构中获取准确坐标的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在做一个边输入边编辑的前端功能,就是用户选中div里面的内容之后,需要给加个高亮的效果,这个简单,给选中的内容直接嵌套一个带border的div就行了,本来这块也没啥,真正头大的是需要给后台发送选中内容在整个串里的开始结束下标,当时搜了一大堆.说用什么anchorOffsetfocusOffset,
在这里插入图片描述
在这里插入图片描述
先说一下,这两个属性是没有问题的,确确实实是可以获取到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也没关系啊/开心
,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值