textArea中获取文本相对于浏览器的位置
最近有个需求,需要获取textArea选中的内容相对于浏览器的位置,然后根据位置生成一个tip。我从来没接触过这块,当然是问AI了,结果AI给出的结果运行起来并不正确,最后在几次对AI的调教后,再根据自己的改写,终于有了靠谱的答案,不多说,先上代码:
const getTextAreaSelectionPosition = (textarea) => { if (textarea.selectionStart === textarea.selectionEnd) { return null; // 没有选中文本 } const start = textarea.selectionStart; const end = textarea.selectionEnd; // 创建一个临时的 div 来模拟 textarea 的样式和内容 const tempDiv = document.createElement('div'); const tempSpan = document.createElement('span'); // 复制 textarea 的样式到临时 div const textareaStyle = window.getComputedStyle(textarea); tempDiv.style.position = 'fixed'; // 使用 fixed 定位,确保相对于视口 tempDiv.style.whiteSpace = 'pre-wrap'; tempDiv.style.wordWrap = 'break-word'; tempDiv.style.top = `${textarea.getBoundingClientRect().top}px`; // 相对于视口的 top tempDiv.style.left = `${textarea.getBoundingClientRect().left}px`; // 相对于视口的 left tempDiv.style.width = `${textarea.clientWidth}px`; tempDiv.style.height = 'auto'; // 高度自适应 tempDiv.style.fontFamily = textareaStyle.fontFamily; tempDiv.style.fontSize = textareaStyle.fontSize; tempDiv.style.lineHeight = textareaStyle.lineHeight; tempDiv.style.padding = textareaStyle.padding; tempDiv.style.border = textareaStyle.border; tempDiv.style.overflow = 'hidden'; // 隐藏超出部分 tempDiv.style.visibility = 'hidden'; // 避免闪烁 // 将 textarea 的内容插入到临时 div 中 const text = textarea.value; // 插入选中文本之前的内容 tempDiv.textContent = text.substring(0, start); // 插入选中的文本 tempSpan.textContent = text.substring(start, end); tempDiv.appendChild(tempSpan); // 插入选中文本之后的内容 tempDiv.appendChild(document.createTextNode(text.substring(end))); // 将临时 div 添加到文档中 document.body.appendChild(tempDiv); const range = document.createRange(); range.selectNodeContents(tempSpan); const rects = range.getClientRects(); // //获取全部大小 // let minX = Infinity; // let minY = Infinity; // let maxX = -Infinity; // let maxY = -Infinity; // // for (const rect of rects) { // if (rect.left < minX) minX = rect.left; // if (rect.top < minY) minY = rect.top; // if (rect.right > maxX) maxX = rect.right; // if (rect.bottom > maxY) maxY = rect.bottom; // } // const r = { // x: minX, // 选中区域左上角相对于视口的横坐标 // y: minY, // 选中区域左上角相对于视口的纵坐标 // width: maxX - minX, // 选中区域的宽度 // height: maxY - minY // 选中区域的高度 // }; // // 获取最后一个矩形(即最后一行的位置) const lastRect = rects[rects.length - 1]; // 移除临时 div document.body.removeChild(tempDiv); let r // 返回相对于浏览器视口的坐标 if (lastRect) { r = { x: lastRect.left, // 相对于视口的横坐标 y: lastRect.top, // 相对于视口的纵坐标 width: lastRect.width, height: lastRect.height }; } return r }
细心同学会发现,我这里并没有返回全部选中的区域,而是选择了最后一行,为什么呢?因为这个需求是需要根据最后一行的位置来显示tip的,如果按照全部区域就会变成这样:
如果只按照最后一行就是这样:
这才是我们想要的对不。
发表评论