【问题标题】:How to capture one line of text in a div如何在div中捕获一行文本
【发布时间】:2013-04-19 20:19:54
【问题描述】:

我查看了与此相关的类似 SO 帖子,但没有一个与我正在寻找的内容完全相关。假设我有一些文本,我将其放入一个 div 中,并为该 div 添加一些任意(甚至可能是动态的)宽度。有没有什么方法可以让我以编程方式捕获和操作 div 中的单行文本(例如,捕获每一行文本,然后将其包装在其自己的 span 标签中,或者类似的东西使我能够操作单行)?

我已经能够使用等宽字体完成此操作,并且基本上首先每行创建一个跨度,然后为每个跨度分配相同数量的字符(使用一些额外的代码,因此单词当然不会被截断),但我希望能够使用非等宽字体执行此操作,这当然会导致问题,因为非等宽字体的字符水平间距会有所不同。

var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
    container = $('<div>');
    container.width('100px').html(str).appendTo('body');

这个输出几乎是你所期望的。它是live here。我想弄清楚的:

  1. 是否会在换行时自动插入我可以访问的换行符?

  2. 我可以破解 DOM 中的任何其他机制或属性来操纵 div 中的一行吗?

  3. 是否有另一种我没有想到的方法来保持非等宽文本自然流动的外观,同时能够逐行访问文本?正如我上面所说,我已经通过等宽文本实现了这一点,但我的方法依赖于等宽文本的统一水平间距。

【问题讨论】:

  • 最好的解决方案是可能将每个单词包装在一个跨度中,然后按顺序检查跨度的垂直偏移量。当单词“x+1”的偏移量高于单词“x”时,你已经到了一个新行。
  • 你见过这个吗:stackoverflow.com/questions/4147080/…(例如:jsbin.com/avuku/15
  • 嘿,我只是想让每个人都知道,我想我实际上已经想出了一个非常可靠的答案,下面发布。如果您想从 div 中捕获单行文本,绝对值得一试。

标签: javascript jquery html css


【解决方案1】:

不确定我是否完全理解您的问题,但是...您将能够获得 div 的高度吗?将其除以(CSS 定义的)行高,您应该得到文本行数。

然后你可以检查任何给定字符/单词的位置,方法是创建一个包含原始文本部分的不可见 div,并执行上述技巧来找到它的行。这有帮助吗?

【讨论】:

    【解决方案2】:

    Bob Monteverde 提供了一段非常好的代码来计算字符串宽度here。您可以使用它并开始将字符串宽度与 div 的实际宽度进行比较以查找单行。

    【讨论】:

      【解决方案3】:

      其他答案的建议让我很好奇,所以我对它们进行了测试,这就是我想出的:

      function wrapLines($container) {
          // get the text from the conatiner
          var text = $container.text();
      
          // split the text into words
          var words = text.split(' ');
      
         // wrap each word in a span and add it to a tmp
         var tmp = '';
         tmp += '<span>' + words.join('</span><span>') + '</span> ';
      
         // remove the text from the container, and replace it with the wrapped words
         $container.html($(tmp));
      
          // prepare the offset variable and tmp
          var tmp = '';
          var top = null;
          $container.find('span').each(function(index, word) {
              $word = $(word);
              // if this is the first iteration
              if (top == null) {
                  // set the top
                  top = $word.position().top;
                  // open the first line
                  tmp = '<span class="line">';
              }
      
              // if this is a new line (top is bigger then the previous word)
              if (top < $word.position().top) {
                  // close the previous line and start a new one
                  tmp += '</span><span class="line">';
                  // change the top
                  top = $word.position().top;            
              }
      
              // add the content of the word node + a space
              tmp += $word.text() + ' ';
          });
          // close the last line
          tmp += '</span>';
      
          // remove the content of the conatiner, and replace it with the wrapped lines
          $container.html($(tmp));    
      }
      

      我添加了很多 cmets,但如果有不清楚的地方,请随时询问。

      要查看实际代码(包括一些花哨的颜色 ;-)),请查看我的小提琴:http://jsfiddle.net/yZnp8/1/

      编辑
      我将@orb 中的代码放在我的解决方案旁边:http://jsfiddle.net/yZnp8/5/

      与 Chrome Inspector 的快速比较表明存在很大的性能差异。 @orbs 解决方案需要 754 毫秒和 17 MB,而我的解决方案需要 136 毫秒和 14 MB。

      一点建议,尽量限制您的 DOM 操作(我在小提琴中标记了它们)。它们会减慢您的代码速度,因为浏览器需要重新渲染您的页面。我只做2,而你做3 + 2x number of words + 1x number of lines。这可能是解释速度差异的原因。而且文本越长,差异就会越大。

      不是试图破坏@orb 解决方案,只是想提供帮助并解释差异......

      【讨论】:

      • 你可能是我最喜欢的新人。您不仅添加了小猫,还添加了 RANDOM 小猫!
      • @PeterVR 感谢您提供有效的解决方案。我会接受你的回答。请看一下我发布的答案。我没有将所有单词都包装在一个跨度中。在将下一个单词添加到当前行之前,我只是使用了 visibility:hidden span 来测试下一个单词是否会导致当前行变得大于容器的宽度。
      【解决方案4】:

      我认为发布我为自己的问题提出的解决方案是一个好主意,因为它看起来很优雅。我不必将每个单词都包含在一个跨度中——我只是使用了一个可见性:隐藏测试跨度来查看该行中的下一个单词是否会导致该行在实际添加下一个之前超出容器的宽度字行。当我把每一行放在一起时,我将它们添加到一个数组中。然后我只是通过遍历数组将每一行附加到容器中。它正在直播here(至少有一段时间)。

      /*global console, $, OO*/
      /*jslint browser: true*/
      (function (undefined) {
          "use strict";
      
          $(window).on('load', function (event) {
              var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
                  $container = $('<div>').width('200px').text(str).appendTo('body');
      
              wrapLines($container);
          });
      
          function wrapLines($container) {
              var text = $container.text(),
                  words = text.split(' '),
                  lines = [],
                  line = $('<span>'),
                  tmp = $('<span>').css('visibility', 'hidden').appendTo('body');
      
              $container.text("");
      
              $.each(words, function (index, word) {
                  if (tmp.text(line.text() + " " + word).width() < $container.width()) {
                      line.text(line.text() + " " + word);
                  } else {
                      lines.push(line);
                      line.remove();
                      line = $('<span>');
                      tmp.text("");
                  }
              });
      
              tmp.remove();
      
              for (var kittens = 0 ; kittens < lines.length; kittens++) {
                  lines[kittens].appendTo($container);
                  console.log(lines[kittens].width());
              }
          }
      
      }());
      

      【讨论】:

      • 很高兴您提出了自己的解决方案。我在回答中添加了一些备注。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-23
      • 2017-09-02
      • 2021-11-16
      相关资源
      最近更新 更多