问题 从字符串,javascript获取x像素值文本的最可靠方法


我有一个包含大量文本的字符串, 文本,在我的JavaScript文件中。我也有一个元素, DIV#集装箱 使用可能非标准的样式(使用单独的CSS) line-heightfont-sizefont-face,也许还有其他人。它有一个固定的高度和宽度。

我想获得适合的最大文本量 DIV#集装箱 没有任何字符串溢出。这样做的最佳方法是什么?

这需要能够处理使用标签格式化的文本,例如:

<strong>Hello person that is this is long and may take more than a</strong> 
line and so on.

目前,我有一个适用于纯文本的JQuery插件,代码如下:

// returns the part of the string that cannot fit into the object
$.fn.func = function(str) {
    var height = this.height();

    this.height("auto");
    while(true) {
        if(str == "") {
            this.height(height);
            return str; // the string is empty, we're done
        }

        var r = sfw(str); // r = [word, rest of String] (sfw is a split first word function defined elsewhere
        var w = r[0], s = r[1];

        var old_html = this.html();
        this.html(old_html + " " + w);

        if(this.height() > height)
        {
            this.html(old_html);
            this.height(height);
            return str; // overflow, return to last working version
        }

        str = s;

    }
}

更新:

数据如下所示:

<ol>
  <li>
     <h2>Title</h2>
     <ol>
        <li>Character</li>
        <ol>
          <li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
          <li>Line two can be separated from line one, but not from itself</li>
        </ol>
      </ol>
     <ol>
        <li>This can be split from other</li>
        <ol>
          <li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
          <li>Line two can be separated from line one, but not from itself</li>
        </ol>
      </ol>
   </li>  <li>
     <h2>Title</h2>
     <ol>
        <li>Character</li>
        <ol>
          <li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
          <li>Line two can be separated from line one, but not from itself</li>
        </ol>
      </ol>
     <ol>
        <li>This can be split from other</li>
        <ol>
          <li>Line one that might go on a long time, SHOULD NOT BE BROKEN</li>
          <li>Line two can be separated from line one, but not from itself</li>
        </ol>
      </ol>
   </li>
</ol>

4558
now


起源

我认为你必须填充(一个看不见的副本)容器,直到它破裂 - Pekka 웃
你的意思是你不能只是设置 overflow:hidden; 在上面? - Robert Koritnik
不,我必须知道它显示了多少。 - Aaron Yodaiken
@Leigh:它类似但不重复。 - Robert Koritnik
和这个? stackoverflow.com/questions/4929107/... - JCOC611


答案:


好吧,让我试着解决它;)实际上考虑解决方案我注意到我对你的要求知之甚少,所以我决定开发简单的JavaScript代码并向你展示结果;尝试之后你可以告诉我什么是错的,所以我可以修理/改变它,交易?

我使用纯JavaScript,没有jQuery(如果需要可以重写)。原理类似于你的jQuery插件:

  1. 我们逐个取字符(而不是单词) sfw 功能呢;它可以改变)
  2. 如果它是开始标记的一部分,浏览器不会显示它,所以我没有特别处理它,只是从标记名称和容器的检查高度逐个添加...不知道是不是那么糟糕。我的意思是当我写作 container.innerHTML = "My String has a link <a href='#'"; 在浏览器中,我看到“My String has a link“,所以”未完成“标签不会影响容器的大小(至少在我测试过的所有浏览器中)
  3. 检查容器的大小,如果它大于我们预期的大小,那么之前的字符串(实际上当前字符串没有最后一个字符)就是我们要找的东西
  4. 现在我们必须关闭所有因切割而未关闭的开口标签

用于测试它的HTML页面:

<html>

  <head>
    <style>
    div {
      font-family: Arial;
      font-size: 20px;
      width: 200px;
      height: 25px;
      overflow: hidden;
    }
    </style>
  </head>

  <body>
     <div id="container"> <strong><i>Strong text with <a href="#">link</a> </i> and </strong> simple text </div>

     <script>
     /**
      * this function crops text inside div element, leaving DOMstructure valid (as much as possible ;).
      * also it makes visible part as "big" as possible, meaning that last visible word will be split 
      * to show its first letters if possible
      *
      * @param container {HTMLDivElement} - container which can also have html elements inside
      * @return {String} - visible part of html inside div element given
      */
     function cropInnerText( container ) {
       var fullText = container.innerHTML; // initial html text inside container 
       var realHeight = container.clientHeight; // remember initial height of the container 
       container.style.height = "auto"; // change height to "auto", now div "fits" its content 

       var i = 0;
       var croppedText = "";
       while(true) {
         // if initial container content is the same that cropped one then there is nothing left to do
         if(croppedText == fullText) { 
           container.style.height = realHeight + "px";
           return croppedText;
         }

         // actually append fullText characters one by one...    
         var nextChar = fullText.charAt( i );
         container.innerHTML = croppedText + nextChar;  

         // ... and check current height, if we still fit size needed
         // if we don't, then we found that visible part of string
         if ( container.clientHeight > realHeight ) {
           // take all opening tags in cropped text 
           var openingTags = croppedText.match( /<[^<>\/]+>/g );
           if ( openingTags != null ) {
             // take all closing tags in cropped text 
             var closingTags = croppedText.match( /<\/[^<>]+>/g ) || [];
             // for each opening tags, which are not closed, in right order...
             for ( var j = openingTags.length - closingTags.length - 1; j > -1; j-- ) {
               var openingTag; 
               if ( openingTags[j].indexOf(' ') > -1 ) {
                 // if there are attributes, then we take only tag name
                 openingTag = openingTags[j].substr(1, openingTags[j].indexOf(' ')-1 ) + '>';
               }
               else {
                 openingTag = openingTags[j].substr(1);
               }
               // ... close opening tag to have valid html
               croppedText += '</' + openingTag;
             }
           }

           // return height of container back ... 
           container.style.height = realHeight + "px";
           // ... as well as its visible content 
           container.innerHTML = croppedText;
           return croppedText;
         }

         i++;
         croppedText += nextChar;
       }

     }

     var container = document.getElementById("container");
     var str = cropInnerText( container );
     console.info( str ); // in this case it prints '<strong><i>Strong text with <a href="#">link</a></i></strong>'
   </script>

</body>

可能的改进/变化:

  1. 我不创建任何新的DOM元素,所以我只是重用当前的容器(以确保我考虑到所有的CSS样式);这样我就会一直改变它的内容,但是在获取可见文本后你就可以写了 fullText 如果需要可以回到容器中(我也不会改变)
  2. 逐字处理原始文本将让我们对DOM进行较少的更改(我们将逐字逐句地逐字逐句地写),因此这种方式应该更快。你已经拥有了 sfw 功能,所以你可以轻松改变它。
  3. 热门问题

    不使用eval / new函数的JavaScript模板库 当涉及内部类时,Java继承如何工作 .NET Windows服务的奇怪问题 在.ipa或.app下查找App ID 快速入门XSLT参考[关闭] 如何找出Android应用程序中未使用的资源 Ruby中并发的同步方法[重复] 将std :: chrono :: system_clock :: time_point转换为struct timeval并返回 Google Drive API V3(javascript)更新文件内容 Bootstrap 3.0 - 将元素推到底部 受密码保护的.NET ClickOnce部署? 如何用postgresql安装wordpress coq Set或Type如何成为命题 硒滚动元素进入(中心)视图 在Spring Transaction JUnit测试中自动装配Hibernate会话的正确方法 Git的Dockerfile策略 如何在FOS_PICKFOLDER中使用IFileDialog,同时仍在对话框中显示文件名 在Firefox扩展中复制Google Chrome浏览器操作弹出效果 CakePHP找到MAX 芹菜 - 完成任务的召唤功能 从使用fmemopen创建的流中读取宽字符 .NET是否为每个程序集创建一个字符串实习池? DefaultModelBinder不绑定嵌套模型 Navigator.MediaDevices.getUserMedia()使用了哪些相机通信标准? 选择命名空间名称时应该知道什么? cout Swagger Codegen CLI Java客户端 - 如何正确使用它 一个很好的哈希函数用于采访整数,字符串? Maven 3 ciManagement配置的目的是什么? 如何通过语言文化获取代码页?