很好地截断一个字符串以适合给定的像素宽度 [英] Truncate a string nicely to fit within a given pixel width
问题描述
有时你的字符串必须符合某个像素宽度。此功能尝试有效地执行此操作。请在下面发布您的建议或重构:)
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 onfont-family
andfont-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 ofstyle.display
. To hide it you should use the valuenone
but then the browser don't calculate theoffsetWidth
. Usestyle.visibility="hidden"
instead.- The search for the right length is very inefficient.
- Must escape
</abbr>
"
我为你重写了它并添加了 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) + '…';
// 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;
}
编辑:
在进行测试时,我发现了一些错误。
While testing a little more I found a couple of bugs.
-
我使用
Math.ceil
而不是
意图Math.floor
(我在
上责怪英语不是我原生的
语言)
I used
Math.ceil
instead of the intendedMath.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("<","<").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, 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)) + '…';
// 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;
}
这篇关于很好地截断一个字符串以适合给定的像素宽度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!