有时,您的字符串必须适合一定的像素宽度。该功能试图有效地做到这一点。请在下面发布您的建议或重构:)

function fitStringToSize(str,len) {
    var shortStr = str;
    var f = document.createElement("span");
    f.style.display = 'hidden';
    f.style.padding = '0px';
    document.body.appendChild(f);

    // on first run, check if string fits into the length already.
    f.innerHTML = str;
    diff = f.offsetWidth - len;

    // if string is too long, shorten it by the approximate
    // difference in characters (to make for fewer iterations).
    while(diff > 0)
    {
        shortStr = substring(str,0,(str.length - Math.ceil(diff / 5))) + '…';
        f.innerHTML = shortStr;
        diff = f.offsetWidth - len;
    }

    while(f.lastChild) {
        f.removeChild(f.lastChild);
    }
    document.body.removeChild(f);

    // if the string was too long, put the original string
    // in the title element of the abbr, and append an ellipsis
    if(shortStr.length < str.length)
    {
        return '<abbr title="' + str + '">' + shortStr + '</abbr>';
    }
    // if the string was short enough in the first place, just return it.
    else
    {
        return str;
    }
}

更新:
@some下面的解决方案要好得多;请使用它。

更新2:
现在,代码以gist的形式发布;随意 fork 并提交补丁:)

最佳答案

您的代码有两个问题。

  • 为什么选择/ 5?字符的宽度取决于font-familyfont-size
  • 您必须在缩写名称中转义str(否则,“会使代码无效”)。
  • diff未声明,最终在全局范围内
  • substring不应该那样工作。你使用的是什么浏览器?
  • hidden不是style.display的有效值。要隐藏它,您应该使用值none,但是浏览器不会计算offsetWidth。请改用style.visibility="hidden"
  • 搜索正确长度的效率很低。
  • 必须转义&lt;/abbr&gt;

  • 我为您重写了它,并添加了className,以便您可以使用一种样式来设置font-familyfont-size。 Fooz先生建议您使用鼠标悬停显示整个字符串。这是没有必要的,因为现代浏览器可以为您做到这一点(已通过FF,IE,Opera和Chrome测试)
        function fitStringToSize(str,len,className) {
        var result = str; // set the result to the whole string as default
        var span = document.createElement("span");
        span.className=className; //Allow a classname to be set to get the right font-size.
        span.style.visibility = 'hidden';
        span.style.padding = '0px';
        document.body.appendChild(span);
    
    
        // check if the string don't fit
        span.innerHTML = result;
        if (span.offsetWidth > len) {
            var posStart = 0, posMid, posEnd = str.length;
            while (true) {
                // Calculate the middle position
                posMid = posStart + Math.ceil((posEnd - posStart) / 2);
                // Break the loop if this is the last round
                if (posMid==posEnd || posMid==posStart) break;
    
                span.innerHTML = str.substring(0,posMid) + '&hellip;';
    
                // Test if the width at the middle position is
                // too wide (set new end) or too narrow (set new start).
                if ( span.offsetWidth > len ) posEnd = posMid; else posStart=posMid;
            }
            //Escape
            var title = str.replace("\"","&#34;");
            //Escape < and >
            var body = str.substring(0,posStart).replace("<","&lt;").replace(">","&gt;");
            result = '<abbr title="' + title + '">' + body + '&hellip;<\/abbr>';
        }
        document.body.removeChild(span);
        return result;
        }
    

    编辑:
    在进行更多测试时,我发现了两个错误。
  • 我使用Math.ceil而不是
    预期的Math.floor(我将此归咎于
    说英语不是我的母语
    语言)
  • 如果输入字符串具有html-tags
    那么结果将是不确定的
    (在其中 chop 标记是不好的
    中间还是留下未打开的标签)

  • 改进之处:
  • 在所有位置转义复制到跨度的字符串。您仍然可以使用html-entities,但不允许使用任何标签(将显示<>)
  • 重写了while -statement(这是一个
    快一点,但主要原因
    是为了摆脱那个 bug
    造成额外的回合并摆脱
    中断声明的内容)
  • 将函数重命名为fitStringToWidth

  • 版本2:
    function fitStringToWidth(str,width,className) {
      // str    A string where html-entities are allowed but no tags.
      // width  The maximum allowed width in pixels
      // className  A CSS class name with the desired font-name and font-size. (optional)
      // ----
      // _escTag is a helper to escape 'less than' and 'greater than'
      function _escTag(s){ return s.replace("<","&lt;").replace(">","&gt;");}
    
      //Create a span element that will be used to get the width
      var span = document.createElement("span");
      //Allow a classname to be set to get the right font-size.
      if (className) span.className=className;
      span.style.display='inline';
      span.style.visibility = 'hidden';
      span.style.padding = '0px';
      document.body.appendChild(span);
    
      var result = _escTag(str); // default to the whole string
      span.innerHTML = result;
      // Check if the string will fit in the allowed width. NOTE: if the width
      // can't be determined (offsetWidth==0) the whole string will be returned.
      if (span.offsetWidth > width) {
        var posStart = 0, posMid, posEnd = str.length, posLength;
        // Calculate (posEnd - posStart) integer division by 2 and
        // assign it to posLength. Repeat until posLength is zero.
        while (posLength = (posEnd - posStart) >> 1) {
          posMid = posStart + posLength;
          //Get the string from the beginning up to posMid;
          span.innerHTML = _escTag(str.substring(0,posMid)) + '&hellip;';
    
          // Check if the current width is too wide (set new end)
          // or too narrow (set new start)
          if ( span.offsetWidth > width ) posEnd = posMid; else posStart=posMid;
        }
    
        result = '<abbr title="' +
          str.replace("\"","&quot;") + '">' +
          _escTag(str.substring(0,posStart)) +
          '&hellip;<\/abbr>';
      }
      document.body.removeChild(span);
      return result;
    }
    

    关于javascript - 很好地 chop 字符串以适合给定的像素宽度,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/282758/

    10-13 07:15
    查看更多