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

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

问题描述

有时你的字符串必须符合某个像素宽度。此功能尝试有效地执行此操作。请在下面发布您的建议或重构:)

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;
    }
}

更新:
@下面的某些解决方案是好多了;请使用它。

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

更新2:
代码现在发布为要旨;随意分叉并提交补丁:)

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-family font-size

  • 你必须在abbr标题中逃避 str (否则将使代码无效)。

  • diff 未声明并最终在全局范围内

  • substring 不应该是这样的。你在使用什么浏览器?

  • 隐藏不是的有效值style.display 。要隐藏它,你应该使用值 none 但是浏览器不会计算 offsetWidth 。请使用 style.visibility =hidden

  • 搜索合适的长度非常低效。

  • 必须逃避& lt; / abbr& gt;

  • 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-family font-size 。 Fooz先生建议您使用鼠标悬停来显示整个字符串。这是没有必要的,因为现代浏览器为你做这件事(用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,但不允许使用任何标签(< > 将会显示)

  • 重写 -statement(这是
    稍快一点,但主要原因
    是获得的摆脱
    造成额外轮次并摆脱破损声明
    的错误)

  • 将函数重命名为 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天全站免登陆