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的,如果按照全部区域就会变成这样:

image.png

如果只按照最后一行就是这样:

image.png

这才是我们想要的对不。

评论

0条评论

发表评论

电子邮件地址不会被公开。