我可以将每一行多行文本包装在一个跨度中吗?

IT技术 javascript jquery text
2021-03-07 01:28:37

我一直在试图弄清楚如何做到这一点(如果可能的话)并且已经画了一个空白......

我有一些文本会换行到多行。我想检测每一行,并将其包裹在一个跨度中。最后,我想为循环数组中的每个跨度分配一个类。

例如...!

<div id="quote">
    I have some text that
    wraps onto three lines
    in this container
</div>

我想让我的 jQuery 解析这些行,检测它的换行位置,然后将其转换为:

<div id="quote">
    <span class="red-bg">I have some text that</span>
    <span class="orange-bg">wraps onto three lines</span>
    <span class="yellow-bg">in this container</span>
</div>

我想动态执行此操作的原因是我在响应式模板中执行此操作,因此有时相同的文本只会换行到两行,或者在 iPhone 中可能会换行四行。

这是可行的吗?我发现了这个 -> http://vidasp.net/tinydemos/numberOfLines.html它计算了一个文本块中使用的行数,但这并没有真正扩展到我需要的。

4个回答

似乎您在问如何在浏览器自然包裹的位置拆分文本。不幸的是,这根本不是直截了当的。它也不是健壮的——考虑以下场景:

  • 用户浏览到您的页面,呈现 div 并触发 onload 事件,
  • 从文本节点创建 3 个 span 元素,每行文本换行 1 个,
  • 用户调整浏览器的大小,div 的大小发生变化。

结果是跨度不再与线的起点和终点相关。当然,这种情况可以使用固定宽度的元素来避免,或者您可以在浏览器调整大小时重新调整整个内容,但这只是它如何崩溃的一个示例。

尽管如此,这并不容易。之前出现过一个类似的问题(尽管目标不同)并且出现了两个解决方案,它们在这里都可能有所帮助:

解决方案 1:getClientRects()

实际上不要用跨度换行文本,而是使用getClientRects(). 然后,创建必要的跨度数并在每行文本后面定位/调整它们的大小。

优点

  • 快速地; getClientRects 返回每一行的位置
  • 简单的; 代码比解决方案2更优雅

缺点

  • 换行文本必须包含在行内元素中。
  • 没有样式实际上适用于文本(如字体粗细或字体颜色)。仅对背景颜色或边框等有用。

随答案一起提供的演示显示了如何突出显示当前位于鼠标下方的文本行。

解决方案2:拆分、连接、循环、合并

使用split()方法将文本拆分为数组,并以单词边界或空格作为传递的参数。重新加入所述阵列成一个字符串与</span><span>每个元素之间,敷整个事情与<span></span>,并替换为生成的HTML原始文本节点中包含的元素。现在,遍历每个 span 元素,检查其在容器中的y位置。y位置增加时,您知道您已经到达了一个新行,并且之前的元素可以合并为一个跨度。

优点

  • 每行都可以使用任何 CSS 属性设置样式,例如 font-weight 或 text-decoration。
  • 每行都可以有自己的事件处理程序。

缺点

  • 由于大量的 DOM 和字符串操作而缓慢且笨拙

结论

可能还有其他方法可以实现您的目标,但我自己不确定。 TextNode.splitText(n)当传递要拆分的字符的数字索引时,可以在 twain (!) 中拆分 TextNode。上述解决方案都不是完美的,并且一旦包含元素调整大小,它们都会中断。

非常感谢这个惊人的、全面的回应。getClientRects() 解决方案看起来真的很有趣(抱歉我没有找到它) - 我将调查这条路线作为后者,而非常聪明的也更重 - 我很可能通过第一个实现我的目标。
2021-05-04 01:28:37

我整理了安迪 E(上图)的小提琴实施解决方案 #2。即拆分、连接、循环、合并

这是算法:

var spanInserted = $('#someText').html().split(" ").join(" </span><span>");
var wrapped = ("<span>").concat(spanInserted, "</span>");
$('#someText').html(wrapped);
var refPos = $('#someText span:first-child').position().top;
var newPos;
$('#someText span').each(function(index) {
    newPos = $(this).position().top   
    if (index == 0){
       return;
    }
    if (newPos == refPos){
        $(this).prepend($(this).prev().text() + " ");
        $(this).prev().remove();
    } 
    refPos = newPos;
});

享受...

非常好。这也为我创建了一堆空跨度,我在循环中将其删除。
2021-05-16 01:28:37
var classes = ",red-bg,orange-bg,yellow-bg".split(",")
var txt = $('#quote').html().split("\n")
//this gives you FIVE items because of the leading and trailing CRs
//so we skip the first and last item in the loop
var output = ""
for(var x=1;x<txt.length-1;x++) {
    output = output + "<span class='"+classes[x]+"'>"+txt[x]+"</span>"
}
$('#quote').html(output)
这非常接近!但它会检测代码中的换行符,而不是渲染页面上的换行符。所以我可以在文本中放置一个中断,跨度将正确换行,但在页面上颜色会改变中线,因为浏览器正确地忽略了新行。
2021-04-26 01:28:37
我想我可以使用块级元素而不是使用内联元素,但它们仍然依赖于源代码中的换行符,我不能保证,因为我可能会 GZip 它......
2021-05-14 01:28:37

这将为您提供文本节点,但我不确定它是否有帮助

$("#quote")
  .contents()
  .filter(function() {
    return this.nodeType == 3;
  })