如何突出显示最靠近鼠标的文本行?

IT技术 javascript html text line highlight
2021-03-15 01:32:55

我有一个很长的文本,我想为用户提供阅读帮助:应突出显示当前行。为方便起见,我将只使用鼠标的 Y 坐标(这样,鼠标指针就不会碍事)。我有一个带有 id 的大 DIV,content它填充了整个宽度,还有一个带有content文本类的小 DIV 参见此处的示例)。

我正在使用 jQuery 1.4。如何突出显示最接近当前鼠标位置的文本行?

3个回答

不确定 jQuery 是否会在这里帮助你很多,但你可以看看MSDNMDCelement.getClientRects上记录方法更具体地说,MSDN 上的这个示例与您想要实现的类似,使用巧妙的 z 索引元素突出显示行,该元素位于.divgetClientRects()

您应该能够通过循环遍历文档中返回的 TextRectangle 对象onmousemove并检查鼠标光标的 y 值是否 > 每个矩形的顶部和 < 底部并移动巧妙的 z 索引 div 来实现相同的目的到相同的位置/高度。

当前所有主流浏览器都支持getClientRects().


http://jsbin.com/avuku/15

更新- 在 Chrome、IE6/7/8、Firefox、Opera、Safari 中工作。我在其他浏览器中遇到的最初问题与DIV需要成为display: inline.
再次更新- 对于一些较新的问题,我不得不参考这个答案,所以我花时间更新它以重新计算窗口调整大小的行。看起来其他人也一直在玩,现在是修订版 15。

这就是 Stack Overflow 很棒的原因。
2021-04-24 01:32:55
哦,现在可以跨浏览器工作了吗?然后我会说这赢得了胜利。
2021-04-27 01:32:55
我认为您只需要onresize为窗口添加一个处理程序即可重新填充lines变量,这将非常可靠。
2021-05-05 01:32:55
+1 适用于任意标记,但仍有优化空间(例如,我可以忽略 X 位置的变化并从中获取最后一个 Y 位置,highlighter.style.top并且仅在鼠标离开 DIV 时才执行大部分工作。甚至可能使用悬停侦听器。
2021-05-08 01:32:55
@Peter Bailey:是的,因为集合中的对象是静态的。我在文档中读到了这一点,只是没有时间实施它。
2021-05-10 01:32:55

如果没有显式包装的文本(即换行符或<br>元素),我不知道您如何可行地做到这一点

据我所知,DOM 无法发现特定文本片段的位置,无论是字符还是像素 - 包括我对Range API 的了解- 更不用说动态自然文本可以假设,例如浏览器的文本缩放功能。

但是,如果您能以某种方式设法生成/注入显式行尾,那么我想我有一个解决方案。

编辑

由于 Pekka 的回答中提供了很棒的信息,我拼凑了一个功能原型,但它有一个重要的警告 - 仅适用于纯文本内容。任何出现在元素主体中的 HTML 都将被删除。

jQuery.fn.wrapLines = function( openTag, closeTag )
  {
    var dummy = this.clone().css({
            top: -9999,
            left: -9999,
            position: 'absolute',
            width: this.width()
        }).appendTo(this.parent())
      , text = dummy.text().match(/\S+\s+/g);

    var words = text.length
      , lastTopOffset = 0
      , lines = []
      , lineText = ''
    ;

    for ( var i = 0; i < words; ++i )
    {
      dummy.html(
          text.slice(0,i).join('') +
          text[i].replace(/(\S)/, '$1<span/>') +
          text.slice(i+1).join('')
      );

      var topOffset = jQuery( 'span', dummy ).offset().top;

      if ( topOffset !== lastTopOffset && i != 0 )
      {
        lines.push( lineText );
        lineText = text[i];
      } else {
        lineText += text[i];
      }

      lastTopOffset = topOffset;
    }
    lines.push( lineText );

    this.html( openTag + lines.join( closeTag + openTag ) + closeTag );
  };

  $(function()
  {
    $('p').wrapLines( '<span class="line">', '</span>' );
  });
span.line {
  display: inline;
}
span.line:hover {
  background-color: lightblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p style="max-width:400px">
 one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen twenty twenty-one twenty-two twenty-three
</p>

干得漂亮!!这正是我一直在寻找的
2021-04-24 01:32:55
+1 很棒,很有魅力!现在有两个功能示例。
2021-05-03 01:32:55
不过,去掉 HTML 标签似乎是一个很大的限制。尽管如此,+1 表示俏皮。
2021-05-08 01:32:55

想到的最佳方法是将每一行拆分为一个<span><div>元素,该元素具有一个:hover设置了“highlight”设置CSS 类:

span.line:hover { background-color: lightblue; }

这将是最便宜的解决方案,因为浏览器将自行处理所有突出显示。如果您想要奇特的效果,您仍然可以通过向每一行添加mouseovermouseout事件来实现

当然,困难的部分是在浏览器的换行符处将内容分成几行。您需要动态执行此操作,以便线条实际反映浏览器中断文本的位置。

也许这个问题的公认答案是朝着正确方向迈出的一步:

使用 jQuery 获取特定行

怎么运行的:

它遍历整个元素(实际上是元素的克隆),在每个单词中插入一个元素。跨度的顶部偏移被缓存 - 当这个偏移改变时,我们可以假设我们在一个新行上。

@Andy 在我看来,这种方法的一大优点是 JavaScript 对页面加载很重,但在实际突出显示完成时不会,而进行实时突出显示的解决方案将一直进行计算。此外,我认为 DOM 插入即使在较慢的机器上也是合理的 - 但这当然取决于所使用的方法。人们必须实际将其放在一起并进行一些分析以确保。
2021-04-21 01:32:55
有关使用示例,请参阅我的答案getClientRects()- 它更清晰,而且我认为计算成本并不高,因为返回的集合仅包含具有静态属性的对象。
2021-04-25 01:32:55
我同意,这是一种创造性的方法,但如果有 1000 个单词,它会不会很慢?在这种情况下,您会期望 DOM 插入的成本非常高。
2021-05-04 01:32:55
很好的发现,以及在另一个问题中发现任意文本中一行的一个很好的创造性方法。
2021-05-05 01:32:55