Есть несколько проблем с вашим кодом.
- Почему
/ 5
? Ширина символов зависит от font-family
и font-size
.
- Вы должны экранировать
str
в заголовке abbr (иначе "сделает код недействительным).
diff
не объявлен и попадает в глобальную область
-
substring
не должен работать так. Какой браузер вы используете?
hidden
не является допустимым значением style.display
. Чтобы скрыть это, вы должны использовать значение none
, но тогда браузер не вычисляет offsetWidth
. Вместо этого используйте style.visibility="hidden"
.
- Поиск нужной длины очень неэффективен.
- Должен сбежать
</abbr>
"
Я переписал его для вас и добавил className
, чтобы вы могли использовать стиль для установки font-family
и font-size
. Мистер Фуз предложил использовать указатель мыши, чтобы показать всю строку. В этом нет необходимости, поскольку современные браузеры делают это за вас (протестировано с 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;
}
Edit:
Во время тестирования я обнаружил пару ошибок.
Я использовал Math.ceil
вместо
предназначен Math.floor
(я виню в этом
этот английский не мой родной
язык)
Если во входной строке были html-теги
тогда результат будет неопределенным
(не хорошо обрезать тег в
середина или оставить открытые метки)
Улучшения: * * тысяча пятьдесят-одна
- Избегайте строки, скопированной в span во всех местах. Вы по-прежнему можете использовать html-объекты, но теги не допускаются (
<
и >
будут отображаться)
- переписал
while
заявление (это
немного быстрее, но главная причина
должен был избавиться от ошибки,
вызвал лишние раунды и избавиться
заявления о разрыве)
- Переименована функция в
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;
}