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

Posted

技术标签:

【中文标题】如何突出显示离鼠标最近的文本行?【英文标题】:How can I highlight the line of text that is closest to the mouse? 【发布时间】:2011-01-28 05:24:22 【问题描述】:

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

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

【问题讨论】:

遍历DOM,通过offsetwidth+parent.offsetWidth等获取元素的绝对位置 更新了我的答案以包含一个可能的解决方案。 @Tom -- 除了你链接到的问题比这个问题更新两年,所以从技术上讲,另一个问题是 this i> 一个 @Tom:加上下面的答案(使用getClientRects())适用于具有不同行高的文本。 ;-) 现在两个问题都是重复的。这真是太合适了...... 【参考方案1】:

不确定 jQuery 是否能帮到你,但你可以看看 element.getClientRects 方法,记录在 MSDN 和 MDC 上。更具体地说,MSDN 上的 this example 有点类似于您想要实现的目标,使用巧妙的 z 索引 div 元素突出显示行,该元素位于 getClientRects() 返回的坐标处的文本后面。

您应该能够通过循环遍历文档onmousemove 中返回的 TextRectangle 对象并检查鼠标光标的 y 值是否 > 顶部和

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


http://jsbin.com/avuku/15

已更新 - 适用于 Chrome、IE6/7/8、Firefox、Opera、Safari。我在其他浏览器中遇到的最初问题与 DIV 需要是 display: inline 有关。再次更新 - 对于一些较新的问题,我必须参考这个答案,所以我花时间更新它以重新计算窗口调整大小的行。好像其他人也在玩,现在是第 15 版。

【讨论】:

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

如果没有明确包装的文本(即换行符或<br> 元素),我看不出你怎么能做到这一点。

据我所知,DOM 无法以字符方式也不以像素方式发现特定文本的包裹位置 - 包括我所知道的 @987654321 @ - 更不用说文本可以假设的动态性质,例如浏览器的文本缩放功能。

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

编辑

感谢 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>

【讨论】:

+1 精彩,就像魅力一样!现在有两个函数示例。 不过,去除 HTML 标签似乎是一个很大的限制。不过,+1 表示漂亮。 干得漂亮!!这正是我一直在寻找的【参考方案3】:

想到的最佳方法是将每一行拆分为 &lt;span&gt;&lt;div&gt; 元素,其中包含带有“突出显示”设置集的 :hover CSS 类:

span.line:hover  background-color: lightblue; 

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

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

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

Getting a specific line using jQuery

它是如何工作的:

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

【讨论】:

很好的发现,另一个问题中的一个很好的创造性方法可以发现任意文本中的一行。 我同意,这是一种创造性的方法,但如果有 1000 个字,会不会很慢?在这种情况下,您会认为 DOM 插入会非常昂贵。 @Andy 在我看来,这种方法的最大优点是它在页面加载方面的 javascript 很重,但在实际突出显示完成时不会,而进行实时突出显示的解决方案将进行计算全程。此外,我认为即使在较慢的机器上插入 DOM 也是合理的——但这当然取决于所使用的方法。必须将它们实际放在一起并进行一些分析才能确定。 查看我的答案以获取使用 getClientRects() 的示例 - 它更简洁,而且我认为计算成本不高,因为返回的集合仅包含具有静态属性的对象。

以上是关于如何突出显示离鼠标最近的文本行?的主要内容,如果未能解决你的问题,请参考以下文章

React Native TextInput 抓取突出显示的文本,并在我点击离开时保持突出显示

如何突出显示和检测 CSS 网格行上的鼠标点击?

鼠标悬停后如何突出显示字符?

如何在鼠标悬停 QML 上突出显示图像

如何使用 Javascript 鼠标事件和 CSS 重新创建“突出显示”选择?

如何在鼠标悬停时突出显示图像地图的某些部分?