我有一个很长的文本,我想为用户提供阅读帮助:当前行应该突出显示。为方便起见,我将只使用鼠标的 Y 坐标(这样,鼠标指针就不会碍事)。我有一个带有 id 的大 DIV,content
它填充了整个宽度,还有一个带有content
文本类的小 DIV(参见此处的示例)。
我正在使用 jQuery 1.4。如何突出显示最接近当前鼠标位置的文本行?
不确定 jQuery 是否会在这里为您提供很大帮助,但您可以查看MSDN和MDCelement.getClientRects
上记录的方法。更具体地说, MSDN 上的这个示例有点类似于您想要实现的,使用巧妙的 z-indexed元素突出显示行,该元素位于由返回的坐标处的文本后面。div
getClientRects()
您应该能够通过循环遍历文档中返回的 TextRectangle 对象onmousemove
并检查鼠标光标的 y 值是否>每个矩形的顶部和 < 底部并移动巧妙的 z 索引 div来实现相同的目的到相同的位置/高度。
目前所有主流浏览器都支持getClientRects()
.
更新- 在 Chrome、IE6/7/8、Firefox、Opera、Safari 中工作。我在其他浏览器中遇到的最初问题与DIV
需要display: inline
.
再次更新- 对于一些较新的问题,我不得不参考这个答案,所以我花时间更新它以重新计算窗口调整大小的行。看起来其他人也一直在玩,现在是第 15 版。
<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>
想到的最佳方法是将每一行拆分为一个<span>
或<div>
元素,该元素具有一个:hover
带有“highlight”设置集的 CSS 类:
span.line:hover { background-color: lightblue; }
这将是最便宜的解决方案,因为浏览器将自行处理所有突出显示。如果你想要花哨的效果,你仍然可以通过在每一行添加mouseover
和mouseout
事件来实现。
当然,最困难的部分是在浏览器的换行符处将内容分成几行。您需要动态地执行此操作,以便这些行实际上反映了浏览器中断文本的位置。
也许这个问题的公认答案是朝着正确方向迈出的一步:
这个怎么运作:
它遍历整个元素(实际上是元素的克隆),在每个单词中插入一个元素。跨度的顶部偏移量被缓存——当这个偏移量改变时,我们可以假设我们在一个新的行上。