You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

网站阅读器辅助工具开发:实现鼠标悬停自动高亮文本行

实现精准贴合文本行的阅读高亮浮动框

这个需求我太有共鸣了!长时间读长文时找不到行真的很闹心,手动选文本又麻烦。你提到的浮动框思路完全可行,而且不用给文本套额外标签——核心是利用浏览器原生的文本行位置检测API,让浮动框精准“贴”在鼠标悬停的那一行上,不管屏幕怎么缩放、文本怎么换行都没问题。

核心实现思路

不用去拆分文本或者给每行加标签,我们直接通过鼠标位置找到对应的文本行的精确坐标,然后实时调整浮动框的位置和尺寸。关键用到这两个API:

  • document.caretRangeFromPoint(x, y):根据鼠标坐标获取光标所在的文本范围
  • Range.getClientRects():获取该文本范围对应的所有行的矩形位置(自动适配换行)

完整代码示例

直接复制就能跑,效果立见:

<!DOCTYPE html>
<html>
<head>
  <style>
    /* 模拟你的文章内容容器 */
    .article-content {
      width: 80%;
      margin: 2rem auto;
      font-size: 16px;
      line-height: 1.8;
      color: #333;
    }

    /* 高亮浮动框核心样式 */
    .line-highlight {
      position: fixed;
      background-color: rgba(255, 255, 100, 0.3); /* 半透明黄色,可自定义 */
      border-radius: 3px;
      pointer-events: none; /* 不干扰鼠标点击文本 */
      z-index: 9999;
      transition: opacity 0.1s;
      opacity: 0;
    }
  </style>
</head>
<body>
  <div class="article-content">
    <!-- 这里放你的长篇文章内容 -->
    屏幕上阅读长篇文章时,尤其是字体较小时,我时常会在页面中迷失,记不清刚读到哪一行。为避免这种不便,我通常会在阅读时选中文本以定位阅读位置。因此,我想要开发一个脚本,自动检测光标位置并高亮鼠标悬停的整行文本,无需用户手动操作。我已尝试过一些方案但未找到合适的解决方法,例如通过标签包裹文本以修改其属性的方式不可行,因为文本行的位置会随屏幕分辨率变化。目前我想到的最佳方案是使用“浮动框”跟随光标移动,但希望该框能贴合文本行而非在行间浮动,请问该如何实现?
    <!-- 多复制几段测试换行效果 -->
    屏幕上阅读长篇文章时,尤其是字体较小时,我时常会在页面中迷失,记不清刚读到哪一行。为避免这种不便,我通常会在阅读时选中文本以定位阅读位置。因此,我想要开发一个脚本,自动检测光标位置并高亮鼠标悬停的整行文本,无需用户手动操作。
  </div>

  <!-- 高亮浮动框,初始隐藏 -->
  <div class="line-highlight" id="lineHighlight"></div>

  <script>
    const highlightBox = document.getElementById('lineHighlight');
    const contentContainer = document.querySelector('.article-content');
    let timer = null;

    // 鼠标移动监听+节流,避免频繁计算卡顿
    contentContainer.addEventListener('mousemove', (e) => {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        updateHighlight(e.clientX, e.clientY);
      }, 50);
    });

    // 移出文本容器时隐藏高亮框
    contentContainer.addEventListener('mouseleave', () => {
      highlightBox.style.opacity = '0';
    });

    function updateHighlight(x, y) {
      try {
        // 获取鼠标位置对应的文本范围
        const range = document.caretRangeFromPoint(x, y);
        if (!range) {
          highlightBox.style.opacity = '0';
          return;
        }

        // 获取当前行的矩形信息(跨行文本取第一行即可)
        const rects = range.getClientRects();
        if (rects.length === 0) {
          highlightBox.style.opacity = '0';
          return;
        }

        // 取光标所在行的矩形
        const lineRect = rects[0];

        // 适配页面滚动,调整高亮框位置和尺寸
        highlightBox.style.top = `${lineRect.top + window.scrollY}px`;
        highlightBox.style.left = `${lineRect.left + window.scrollX}px`;
        highlightBox.style.width = `${lineRect.width}px`;
        highlightBox.style.height = `${lineRect.height}px`;
        highlightBox.style.opacity = '1';
      } catch (err) {
        // 兼容部分浏览器的异常情况
        highlightBox.style.opacity = '0';
      }
    }
  </script>
</body>
</html>

关键细节解释

  1. 为什么不用文本标签包裹?
    你之前遇到的换行适配问题,getClientRects()已经帮我们解决了——它会自动计算当前渲染环境下的每行实际位置,完全不用关心文本怎么拆分换行。

  2. 节流函数的作用
    鼠标移动会频繁触发事件,加50ms节流能减少不必要的计算,避免页面卡顿,长篇文章时效果更明显。

  3. pointer-events: none
    这个样式很关键,它让高亮框不拦截鼠标交互,不然你会点不到下面的文本,影响正常阅读。

  4. 滚动适配
    计算位置时加上window.scrollYwindow.scrollX,确保页面滚动时高亮框依然精准贴合文本行。

自定义优化建议

  • 调整background-color可以改变高亮颜色,比如rgba(0, 123, 255, 0.2)就是淡蓝色高亮
  • 如果想要高亮整行(包括容器全宽),可以把width改成contentContainer.offsetWidth,注意要适配容器的padding
  • 可以加个开关按钮,让用户手动开启/关闭高亮功能

内容的提问来源于stack exchange,提问作者Getter

火山引擎 最新活动