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

时间:2010-11-10 17:14:11

标签: javascript jquery text

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

我有一些文字将包裹在多行上。我想检测每条线,并将其包裹在一个范围内。最后,我想从循环数组中为每个范围分配一个类。

例如......!

<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中包含四行。

这可行吗?我发现了这个 - &gt; http://vidasp.net/tinydemos/numberOfLines.html计算文本块中使用的行数,但实际上并没有扩展到我需要的行。

4 个答案:

答案 0 :(得分:9)

好像你问的是如何将文本分割成浏览器自然包装的文本。不幸的是,这根本不是直截了当的。它也不健壮 - 请考虑以下情况:

  • 用户浏览您的页面,渲染div并触发onload事件,
  • 从文本节点创建3个span元素,每个包装的文本行创建1个
  • 用户调整浏览器大小并更改div的大小。

结果是跨度不再与线的开始和结束位置相关联。当然,使用固定宽度的元素可以避免这种情况,或者你可以在浏览器调整大小时重新调整整个内容,但这只是它如何破坏的一个例子。

但是,这并不容易。之前有一个similar question(尽管目标不同),出现了两个解决方案,这两个方面都有帮助:

Solution 1: getClientRects()

实际上不要将文本换成跨度,而是使用getClientRects()获取每行文本的位置和尺寸。然后,创建所需的跨距数,并在每行文本后面定位/调整它们的大小。

<强>赞成

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

<强>缺点

  • 包装文本必须包含在内联元素中。
  • 实际上没有样式应用于文本(如font-weight或font-color)。仅适用于背景颜色或边框等内容。
带有答案的

The demo provided显示了如何突出显示当前鼠标下方的文本行。

Solution 2: Split, join, loop, merge

使用 split()方法将文本拆分为数组,并将字边界或空格作为参数传递。将数组重新连接到每个元素之间带有</span><span>的字符串,并用<span></span>包装整个事物,并用包含元素中的结果HTML替换原始文本节点。现在,迭代每个span元素,检查容器中的 y 位置。当 y 位置增加时,您知道已到达新行,并且之前的元素可以合并为单个范围。

<强>赞成

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

<强>缺点

  • 由于众多DOM和字符串操作而导致缓慢而笨拙

结论

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

答案 1 :(得分:6)

我将Andy E(上图)实施解决方案#2的a fiddle放在一起。即拆分,加入,循环,合并

这是算法:

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;
});

...享受

答案 2 :(得分:1)

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)

答案 3 :(得分:0)

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

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