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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4147080/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 10:29:57  来源:igfitidea点击:

Can I wrap each line of multi-line text in a span?

javascriptjquerytext

提问by BellamyStudio

I've been trying to figure out how to do this (if it's even possible) and have drawn a blank...

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

I have some text that will wrap onto multiple lines. I want to detect each individual line, and wrap it in a span. Finally, I want to assign a class to each span from a looping array.

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

For example...!

例如...!

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

I want to get my jQuery to parse those lines, detect where it wraps, and turn it into this:

我想让我的 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>

The reason that I want to do this dynamically is that I'm doing it within responsive templates, so sometimes the same text will only wrap onto two lines, or maybe four in an iPhone.

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

Is this doable? I've found this -> http://vidasp.net/tinydemos/numberOfLines.htmlwhich calculates the number of lines used in a block of text, but that doesn't really extend to do what I need.

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

回答by Andy E

It seems like you're asking how to split the text where it is naturally wrapped by the browser. Unfortunately, this isn't straightforward at all. Neither is it robust — consider the following scenario:

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

  • User browses to your page, the div is rendered and the onload event fires,
  • 3 span elements are created from the text node, 1 for each wrapped line of text,
  • The user resizes the browser and the size of the div changes.
  • 用户浏览到您的页面,呈现 div 并触发 onload 事件,
  • 从文本节点创建 3 个 span 元素,每行文本换行 1 个,
  • 用户调整浏览器的大小,div 的大小发生变化。

The result is that the spans no longer correlate to where the lines start and finish. Of course, this scenario is avoidable using fixed-width elements or you can rejig the whole thing when the browser resizes, but that's just an example of how it can break.

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

Still, it's not easy. A similar questionhas come up before (albeit, with a different goal) and two solutions appeared, which could both be of help here:

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

Solution 1: getClientRects()

解决方案 1:getClientRects()

Don't actually wrap the text in spans, but get the position and dimensions of each line of text using getClientRects(). Then, create the number of spans necessary and position/resize them behind each line of text.

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

Pros

优点

  • Fast; getClientRects returns the position of each line
  • Simple; the code is more elegant than solution 2
  • 快速地; getClientRects 返回每一行的位置
  • 简单的; 代码比解决方案2更优雅

Cons

缺点

  • Wrapped text must be contained by an inline element.
  • No styling will actually apply to the text (like font-weight or font-color). Only useful for things like background-color or border.
  • 换行文本必须包含在行内元素中。
  • 没有样式实际上适用于文本(如字体粗细或字体颜色)。仅对背景颜色或边框等有用。

The demo providedwith the answer shows how you can highlight the line of text currently beneath the mouse.

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

Solution 2: Split, join, loop, merge

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

Split the text into an array using the split()method with a word boundary or white-space as the argument passed. Rejoin the array into a string with </span><span>between each element and wrap the whole thing with <span>and </span>, and replace the original text node with the resulting HTML in the containing element. Now, iterate over each of those span elements checking its yposition within the container. When the yposition increases, you know that you've reached a new line and the previous elements can be merged into a single span.

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

Pros

优点

  • Each line can be styled with any CSS property, like font-weight or text-decoration.
  • Each line can have its own event handlers.
  • 每行都可以使用任何 CSS 属性设置样式,例如 font-weight 或 text-decoration。
  • 每行都可以有自己的事件处理程序。

Cons

缺点

  • Slow and unwieldy due to the numerous DOM and string operations
  • 由于大量的 DOM 和字符串操作而缓慢且笨拙

Conclusion

结论

There may be other ways to achieve your goal, but I'm not sure of any myself. TextNode.splitText(n)can split a TextNode in twain (!) when passed a numeric index of the character you want to split on. Neither of the above solutions are perfect, and both break as soon as the containing element resizes.

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

回答by user2959735

I put together a fiddleimplementing solution #2 by Andy E (above). I.e. Split, join, loop, merge

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

Here's the algorithm:

这是算法:

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

Enjoy...

享受...

回答by Diodeus - James MacFarlane

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)

回答by John Hartsock

This will get you the text node but I'm not sure it helps

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

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