很好地截断字符串以适应给定的像素宽度 [英] Truncate a string nicely to fit within a given pixel width

查看:14
本文介绍了很好地截断字符串以适应给定的像素宽度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Sometimes you have strings that must fit within a certain pixel width. This function attempts to do so efficiently. Please post your suggestions or refactorings below :)

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 下面的解决方案要好得多;请使用那个.

UPDATE: @some's solution below is much better; please use that.

更新 2:代码现在作为 gist 发布;随意 fork 和提交补丁:)

Update 2: Code now posted as a gist; feel free to fork and submit patches :)

推荐答案

您的代码存在一些问题.

There are a couple of problems with your code.

  • 为什么是 /5 ?字符的宽度取决于font-familyfont-size.
  • 您必须在 abbr 标题中转义 str(否则 " 会使代码无效).
  • diff 未声明并在全局范围内结束
  • substring 不应该这样工作.您使用的是什么浏览器?
  • hidden 不是 style.display 的有效值.要隐藏它,您应该使用 none 值,但浏览器不会计算 offsetWidth.改用 style.visibility="hidden".
  • 寻找正确长度的效率非常低.
  • 必须转义 &lt;/abbr>"
  • Why / 5 ? The width of the characters depends on font-family and font-size.
  • You must escape str in the abbr title (or else an " will make the code invalid).
  • diff is not declared and ends up in the global scope
  • The substring is not supposed to work like that. What browser are you using?
  • hidden is not a valid value of style.display. To hide it you should use the value none but then the browser don't calculate the offsetWidth. Use style.visibility="hidden" instead.
  • The search for the right length is very inefficient.
  • Must escape &lt;/abbr&gt;"

我为您重写并添加了className,以便您可以使用样式来设置font-familyfont-size.福兹先生建议您使用鼠标悬停来显示整个字符串.这不是必需的,因为现代浏览器会为您执行此操作(已使用 FF、IE、Opera 和 Chrome 进行测试)

I rewrote it for you and added className so you can use a style to set the font-family and font-size. Mr Fooz suggested that you use a mouseover to show the whole string. That is not necessary since modern browsers do that for you (tested with FF, IE, Opera and 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;
    }

在进行更多测试时,我发现了一些错误.

While testing a little more I found a couple of bugs.

  • 我使用了 Math.ceil 而不是预期 Math.floor (我把这归咎于英语不是我的母语语言)

  • I used Math.ceil instead of the intended Math.floor (I blame this on that English isn't my native language)

如果输入字符串有 html-tags那么结果将是未定义的(截断标签不好中间或留下开放标签)

If the input string had html-tags then the result would be undefined (it's not good to truncate a tag in the middle or to leave open tags)

改进:

  • 转义复制到所有位置的跨度的字符串.您仍然可以使用 html-entities,但不允许使用标签(<> 将被显示)
  • 重写了 while 语句(它是一个快一点,但主要原因是为了摆脱这个错误造成额外的回合并摆脱中断语句)
  • 将函数重命名为fitStringToWidth
  • Escape the string that is copied to the span on all places. You can still use html-entities, but no tags are allowed (< and > will be displayed)
  • Rewrote the while-statement (it is a little faster, but the main reason was to get rid of the bug that caused extra rounds and to get rid of the break-statement)
  • Renamed the function to 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;
}

这篇关于很好地截断字符串以适应给定的像素宽度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆