有时你有一些字符串必须适合一定的像素宽度.此功能尝试有效地执行此操作.请在下面发布您的建议或重构:)
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,(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; } }
更新:
@一些下面的解决方案好多了;请使用.
解决方法
你的代码有几个问题.
>为什么/ 5?字符的宽度取决于font-family和font-size.
>你必须在abbr标题中转义str(否则“将使代码无效”).
> diff不被声明,并且结束于全局范围
>子串不应该这样工作.你使用的是什么浏览器?
> hidden不是style.display的有效值.要隐藏它,你应该使用值none,但是浏览器不会计算offsetWidth.改用style.visibility =“隐藏”.
搜索正确的长度是非常低效的.
>必须逃脱& lt; / abbr& gt“
我为您重写了它,并添加了className,因此您可以使用样式来设置font-family和font-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) + '…'; // 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("\"","""); //Escape < and > var body = str.substring(0,posStart).replace("<","<").replace(">",">"); result = '<abbr title="' + title + '">' + body + '…<\/abbr>'; } document.body.removeChild(span); return result; }
编辑:
在测试一下我发现了几个bug.
我用Math.ceil代替了
打算Math.floor(我责怪这个
那个英文不是我的母语
语言)
>如果输入的字符串有html标签
那么结果将是未定义的
(截断标签是不好的
中间或离开打开的标签)
改进:
>删除所有地方复制到跨度的字符串.您仍然可以使用html实体,但不允许使用标签(<和>将被显示)
>重写while语句(它是一个
更快,但主要原因
是摆脱那个bug
造成额外的回合和摆脱
的break-statement)
>将函数重命名为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("<",">");} //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,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)) + '…'; // 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("\"",""") + '">' + _escTag(str.substring(0,posStart)) + '…<\/abbr>'; } document.body.removeChild(span); return result; }