我有一个包含大量文本的字符串, 文本,在我的JavaScript文件中。我也有一个元素, DIV#集装箱 使用可能非标准的样式(使用单独的CSS) line-height, font-size, font-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>
             
            
            
            
好吧,让我试着解决它;)实际上考虑解决方案我注意到我对你的要求知之甚少,所以我决定开发简单的JavaScript代码并向你展示结果;尝试之后你可以告诉我什么是错的,所以我可以修理/改变它,交易?
我使用纯JavaScript,没有jQuery(如果需要可以重写)。原理类似于你的jQuery插件:
- 我们逐个取字符(而不是单词) 
sfw 功能呢;它可以改变) 
- 如果它是开始标记的一部分,浏览器不会显示它,所以我没有特别处理它,只是从标记名称和容器的检查高度逐个添加...不知道是不是那么糟糕。我的意思是当我写作 
container.innerHTML = "My String has a link <a href='#'"; 在浏览器中,我看到“My String has a link“,所以”未完成“标签不会影响容器的大小(至少在我测试过的所有浏览器中) 
- 检查容器的大小,如果它大于我们预期的大小,那么之前的字符串(实际上当前字符串没有最后一个字符)就是我们要找的东西
 
- 现在我们必须关闭所有因切割而未关闭的开口标签 
 
用于测试它的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>
可能的改进/变化:
- 我不创建任何新的DOM元素,所以我只是重用当前的容器(以确保我考虑到所有的CSS样式);这样我就会一直改变它的内容,但是在获取可见文本后你就可以写了 
fullText 如果需要可以回到容器中(我也不会改变) 
- 逐字处理原始文本将让我们对DOM进行较少的更改(我们将逐字逐句地逐字逐句地写),因此这种方式应该更快。你已经拥有了 
sfw 功能,所以你可以轻松改变它。  
- 如果我们有两个字 
"our sentence",有可能只有第一个可见("our"),并且应该削减“句子”(overflow:hidden 会这样工作)。在我的情况下,我将逐个字符追加,所以我的结果可以 "our sent"。同样,这不是算法的复杂部分,因此基于您的jQuery插件代码,您可以更改我的单词。 
问题,评论,发现的错误是受欢迎的;)我在IE9,FF3.6,Chrome 9中进行了测试
更新: 遇到问题 <li>, <h1> ......例如我有容器内容:
<div id="container"> <strong><i>Strong text with <ul><li>link</li></ul> </i> and </strong> simple text </div>
在这种情况下,浏览器的行为方式(逐个字符串,容器中的内容以及根据算法显示的内容):
...
"<strong><i>Strong text with <" -> "<strong><i>Strong text with <"
"<strong><i>Strong text with <u" -> "<strong><i>Strong text with "
"<strong><i>Strong text with <ul" -> "<strong><i>Strong text with <ul></ul>" // well I mean it recognizes ul tag and changes size of container
算法的结果是字符串 "<strong><i>Strong text with <u</i></strong>"  - 用 "<u"什么不好。在这种情况下我需要处理的是,如果我们找到了结果字符串("<strong><i>Strong text with <u" 根据算法),我们需要删除最后一个“未闭合”标签("<u" 在我们的例子中),所以在关闭标签以获得有效的html之前我添加了以下内容:
...
if ( container.clientHeight > realHeight ) {
  /* start of changes */
  var unclosedTags = croppedText.match(/<[\w]*/g);
  var lastUnclosedTag = unclosedTags[ unclosedTags.length - 1 ];
  if ( croppedText.lastIndexOf( lastUnclosedTag ) + lastUnclosedTag.length == croppedText.length ) {
    croppedText = croppedText.substr(0, croppedText.length - lastUnclosedTag.length );
  }
  /* end of changes */
  // take all opening tags in cropped text 
...
可能有点懒惰的实现,但它可以调整,如果它减慢。这里做了什么
- 不带所有标签 
> (在我们的例子中,它返回 ["<strong", "<i", "<u"]);  
- 拿最后一个(
"<u") 
- 如果它结束了 
croppedText 字符串,然后我们删除它 
完成后,结果字符串变为 "<strong><i>Strong text with </i></strong>"
UPDATE2 谢谢你的例子,所以我看到你没有嵌套标签,但它们也有“树”结构,实际上我没有考虑到它,但它仍然可以修复;)一开始我想要编写我的相应“解析器”,但是当我不工作的时候我总是得到一个例子,所以我认为最好找到已编写的解析器,并且有一个: 纯JavaScript HTML解析器。还有一个 粗毛 它:
虽然这个图书馆没有涵盖
  完全可能的奇怪之处
  HTML提供,它确实处理了很多
  最明显的东西。
但是对于你的例子它是有效的;那个图书馆没有考虑开放标签的位置,但是 
- 我们依靠原始的html结构很好(没有破坏);
 
- 我们在结果“字符串”的末尾关闭标签(所以这没关系)
 
我认为有了这个假设,这个库很好用。然后结果函数看起来像:
<script src="http://ejohn.org/files/htmlparser.js"></script>
 <script>
 function cropInnerText( container ) {
   var fullText = container.innerHTML;
   var realHeight = container.clientHeight;
   container.style.height = "auto";
   var i = 0;
   var croppedText = "";
   while(true) {
     if(croppedText == fullText) { 
       container.style.height = realHeight + "px";
       return croppedText;
     }
     var nextChar = fullText.charAt( i );
     container.innerHTML = croppedText + nextChar;  
     if ( container.clientHeight > realHeight ) {
       // we still have to remove unended tag (like "<u" - with no closed bracket)
       var unclosedTags = croppedText.match(/<[\w]*/g);
       var lastUnclosedTag = unclosedTags[ unclosedTags.length - 1 ];
       if ( croppedText.lastIndexOf( lastUnclosedTag ) + lastUnclosedTag.length == croppedText.length ) {
         croppedText = croppedText.substr(0, croppedText.length - lastUnclosedTag.length );
       }
       // this part is now quite simple ;)
       croppedText = HTMLtoXML(croppedText);
       container.style.height = realHeight + "px";
       container.innerHTML = croppedText ;
       return croppedText;
     }
     i++;
     croppedText += nextChar;
   }
 }
 </script>
 
                
要获得最长的第一行:
- 用它创建一个DIV 
visibility:hidden; (因此它将具有尺寸)但将其定位为 position:absolute; 所以它不会破坏你的页面流 
- 将其类型样式设置为与结果相同的值 
DIV 
- 设置它的高度与结果相同 
DIV 但保持 width:auto; 
- 添加文字
 
- 保持切断文字直到宽度下降到最终结果 
DIV的宽度。 
结果是您可以放入的文本。
如果需要查找数量,请调整算法 线 适合容器保存 height:auto; 并设置固定 width。
自动调整textareas使用相同的技术,当用户键入文本时,textareas会自动增长。
 
                
要解决此问题,您将需要其他信息:
- 我应该在哪里“切”输入文字
 
- 切碎它,我该如何修复这两半,以便我可以把每一个都塞进DIV?
 
至于“在哪里砍”问题,你可能需要注入独特的 <a name="uniq"/> 在输入字符串中的关键点处锚定标记(比如......在输入中的每个开始标记之前?)。然后,您可以测试每个锚点的布局位置并找到中断输入的位置。
找到最合理的断点,你需要在前半部分的末尾添加标签以关闭它,并在下半部分的前面添加标签以打开它。因此,当您解析输入字符串以便先找到开始标记时,您在注入时会保留一个“标记堆栈”列表 <a/>。查找与此paritcular相关的标记堆栈,然后根据需要添加标记。
我可以发现2个陷阱:
- 如果输入标签具有属性,则需要保留有关每个中断的更多信息
 
- 您可能需要将某些标签视为“牢不可破”并在之前进行中断 
<a/> 代替 
最终,在我看来,你正在等待HTML5的列构造。
 
                
你只是想格式化 第一行 在一个段落?请问CSS :第一行 伪选择器适用于您的应用程序?
 
                
你可以用 的getComputedStyle 找出内联元素的宽度(即它有 display: inline 属性):
window.getComputedStyle(element, null).getPropertyValue("width");
如果事实证明此元素的宽度大于其容器的宽度,则会逐步删除一些文本,直到它适合。