Расчет ширины текста


101

Я пытаюсь рассчитать ширину текста с помощью jQuery. Не знаю, что, но я определенно делаю что-то не так.

Итак, вот код:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);

Итак, каким образом этот код не работает? Что нужно сделать по-другому?
Сикстен Отто

Ответы:


142

У меня это сработало лучше:

$.fn.textWidth = function(){
  var html_org = $(this).html();
  var html_calc = '<span>' + html_org + '</span>';
  $(this).html(html_calc);
  var width = $(this).find('span:first').width();
  $(this).html(html_org);
  return width;
};

4
+1 - это действительно измеряет текст, а не только содержащий элемент блока, как решение brainreavis.
Бен

Slick. +1. Похоже, вам не хватает точки с запятой в третьей строке после '</span>', хотя это, похоже, не имеет значения (работает с ней или без нее на FF9).
shmeeps

21
Однако будьте осторожны ... этот метод отвяжет любые события дочерних элементов.
brianreavis 03

Я пытался использовать эту функцию разными способами, но она продолжает возвращать значение null. Может ли кто-нибудь опубликовать синтаксис того, как на самом деле используется эта функция? Могу ли я запустить функцию .textWidth () для объекта jQuery? Могу ли я передать текст в эту функцию? Могу ли я запускать эту функцию как функцию jQuery (например, $ .textWidth (jqObject)? Потому что ни один из этих параметров, похоже, не работает. Спасибо ...
moosefetcher

2
@moosefetcher вы бы сделали $ (selector) .textWidth (); Посмотрите здесь learn.jquery.com/plugins/basic-plugin-creation/…
uesports135

89

Вот функция, которая лучше, чем другие опубликованные, потому что

  1. это короче
  2. он работает при пропускании <input>, <span>или "string".
  3. это быстрее для частого использования, потому что он повторно использует существующий элемент DOM.

Демо: http://jsfiddle.net/philfreo/MqM76/

// Calculate width of text from DOM element or string. By Phil Freo <http://philfreo.com>
$.fn.textWidth = function(text, font) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
    $.fn.textWidth.fakeEl.text(text || this.val() || this.text()).css('font', font || this.css('font'));
    return $.fn.textWidth.fakeEl.width();
};

1
Вот Это Да! Настоящее великолепие!
Мишель Триана

3
Отличное решение, я думаю, должен быть принят ответ! Спасибо, приятель!
Илья Ростовцев

Фантастико! Просто и чисто.
Кэри Эстес

Это хорошо, но не обрабатывает пробелы. См. Ответ @ edsioufi для улучшения этого решения.
Badgerpot

Если внутри элемента есть скрытый текст, он будет искажать вашу ширину. Чтобы учесть это, не забудьте удалить скрытые узлы перед вычислением ширины текста. Чтобы безопасно удалить скрытые узлы, вам, вероятно, следует сначала создать клон и выполнить удаление там.
thdoan

36

Мое решение

$.fn.textWidth = function(){
    var self = $(this),
        children = self.children(),
        calculator = $('<span style="display: inline-block;" />'),
        width;

    children.wrap(calculator);
    width = children.parent().width(); // parent = the calculator wrapper
    children.unwrap();
    return width;
};

По сути, улучшение по сравнению с Рунами, которое не .htmlтак легко использовать


Автор Ajarn Gerhard, который разместил это в качестве ответа: Это не работает в IE8, потому что вам не хватает /перед закрывающей скобкой <span>тега:calculator = $('<span style="display: inline-block;" />'),
Петр Р.

1
Кажется, что это возвращает null, если под измеряемым элементом есть дочерний элемент. Можно ли заставить его работать без дочернего элемента? См. Jsfiddle.net/h22tj/41
Casper

+1 - Я никогда не знал, что есть разворачивание (), которое доставило мне бесконечное горе.
Orwellophile

Он всегда возвращает null в Chrome.
emeraldhieu

12

Эти textWidthфункции , предусмотренные в ответах , и которые принимают в stringкачестве аргумента , не будет составлять начальную и конечные пробела (те , которые не отображаются в контейнере фиктивного). Кроме того, они не будут работать, если текст содержит какую-либо разметку html (подстрока <br>не будет производить никакого вывода и &nbsp;вернет длину одного пробела).

Это проблема только для textWidthфункций, которые принимают a string, потому что, если элемент DOM задан и .html()вызывается элементом, то, вероятно, нет необходимости исправлять это для такого варианта использования.

Но если, например, вы вычисляете ширину текста для динамического изменения ширины текстового inputэлемента в зависимости от типов пользователей (мой текущий вариант использования), вы, вероятно, захотите заменить начальные и конечные пробелы на &nbsp;и закодировать строку в html.

Я использовал решение philfreo, поэтому вот его версия, которая это исправляет (с комментариями к дополнениям):

$.fn.textWidth = function(text, font) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').appendTo(document.body);
    var htmlText = text || this.val() || this.text();
    htmlText = $.fn.textWidth.fakeEl.text(htmlText).html(); //encode to Html
    htmlText = htmlText.replace(/\s/g, "&nbsp;"); //replace trailing and leading spaces
    $.fn.textWidth.fakeEl.html(htmlText).css('font', font || this.css('font'));
    return $.fn.textWidth.fakeEl.width();
};

Спасибо. Ваш ответ очень ценен.
Vishal

1
Как ни странно, когда я попробовал этот, он неправильно скопировал font-size. Пришлось добавить, css('font-size'), this.css('font-size'))чтобы он заработал. Любые идеи, почему fontодно не копирует это значение?
Gone Coding

@GoneCoding Где вы добавили эти дополнения?
webmagnets 05

@webmagnets: то же место, что и существующий .cssметод, но я вижу, что мои скобки неправильные. Должно быть css('font-size', this.css('font-size')).
Gone Coding

11

Функции ширины jQuery могут быть немного сомнительными при попытке определить ширину текста из-за несовместимых блочных моделей. Верным способом было бы вставить div внутри вашего элемента, чтобы определить фактическую ширину текста:

$.fn.textWidth = function(){
  var sensor = $('<div />').css({margin: 0, padding: 0});
  $(this).append(sensor);
  var width = sensor.width();
  sensor.remove();
  return width;
};

Чтобы использовать этот мини-плагин, просто:

$('.calltoaction').textWidth();

1
Разве это не даст вам ширину блока, а не текст?
Джош Рикард,

-1 Это действительно похоже на измерение ширины поля, а не ширины текста.
Натан Артур

1
Разве простое использование диапазона вместо div не решит проблему ширины? Если да, то эта функция немного лучше принятого ответа.
Джош

@Josh: Если вы замените его на, spanвы просто получите ноль. Пробовал это решение на H2, где у родительских элементов скрыто переполнение, и я получаю только усеченную длину текста. Возможно, объяснение того, как это должно работать , поможет улучшить его работу?
Gone Coding

8

Я обнаружил, что это решение работает хорошо, и оно наследует исходный шрифт перед изменением размера:

$.fn.textWidth = function(text){
  var org = $(this)
  var html = $('<span style="postion:absolute;width:auto;left:-9999px">' + (text || org.html()) + '</span>');
  if (!text) {
    html.css("font-family", org.css("font-family"));
    html.css("font-size", org.css("font-size"));
  }
  $('body').append(html);
  var width = html.width();
  html.remove();
  return width;
}

1
В итоге я использовал это, но добавил org.css("font-weight"). Также я бы сказал, что эта if(!text)часть не интуитивно понятна. Если я использую, например, jQuery("#someContainer").textWidth("Lorem ipsum")я хотел бы знать ширину текста «Lorem ipsum» при применении в этом конкретном контейнере.
Sleavely

8

Ни Rune, ни Brain у меня не работали в том случае, если элемент, содержащий текст, имел фиксированную ширину. Я сделал что-то похожее на Окамеру. Он использует меньше селекторов.

РЕДАКТИРОВАТЬ: это, вероятно, не сработает для элементов, которые используют относительные font-size, поскольку следующий код вставляет htmlCalcэлемент в, bodyтаким образом, теряет информацию о родительских отношениях.

$.fn.textWidth = function() {
    var htmlCalc = $('<span>' + this.html() + '</span>');
    htmlCalc.css('font-size', this.css('font-size'))
            .hide()
            .prependTo('body');
    var width = htmlCalc.width();
    htmlCalc.remove();
    return width;
};

Для меня это было лучшее решение с поддержкой IE8, и оно не нарушит никаких привязок к элементу в процессе! Спасибо.
ouija

Примечание. В методе расширения jQuery thisуже является объектом jQuery, поэтому $(this)он избыточен.
Gone Coding

У меня это сработало неправильно, потому что рассчитанная ширина слишком мала. Принятый ответ сработал правильно
PandaWood

5

Если вы пытаетесь сделать это с текстом в поле выбора или если эти два не работают, попробуйте это вместо этого:

$.fn.textWidth = function(){
 var calc = '<span style="display:none">' + $(this).text() + '</span>';
 $('body').append(calc);
 var width = $('body').find('span:last').width();
 $('body').find('span:last').remove();
 return width;
};

или

function textWidth(text){
 var calc = '<span style="display:none">' + text + '</span>';
 $('body').append(calc);
 var width = $('body').find('span:last').width();
 $('body').find('span:last').remove();
 return width;
};

если вы хотите сначала схватить текст


4

дело в том, что вы делаете неправильно, что вы вызываете метод cTxt, который представляет собой простую строку, а не объект jQuery. cTxt - это действительно содержащийся текст.


2

Небольшое изменение для Нико, поскольку .children () вернет пустой набор, если мы ссылаемся на текстовый элемент, такой как h1 или p . Поэтому мы будем использовать .contents () вместо этого и использовать this вместо $ (this), поскольку мы создаем метод для объекта jQuery.

$.fn.textWidth = function(){
    var contents = this.contents(),
        wrapper  = '<span style="display: inline-block;" />',
        width    = '';

    contents.wrapAll(wrapper);
    width = contents.parent().width(); // parent is now the wrapper
    contents.unwrap();
    return width;
    };

1

после двух дней погони за призраком, пытаясь понять, почему ширина текста была неправильной, я понял, что это было из-за пробелов в текстовой строке, которые остановили вычисление ширины.

Итак, еще один совет - проверить, не вызывают ли пробелы проблемы. использовать

&nbsp;

неразрывное пространство и посмотрите, исправит ли это его.

другие функции, которые люди предлагали, тоже работают хорошо, но проблемы вызывают пробелы.


Просто временно добавьте white-space: nowrapвстроенный CSS, чтобы избежать этого.
Gone Coding

1

Если вы пытаетесь определить ширину комбинации текстовых узлов и элементов внутри данного элемента, вам необходимо обернуть все содержимое с помощью wrapInner () , вычислить ширину, а затем развернуть содержимое.

* Примечание. Вам также потребуется расширить jQuery, чтобы добавить функцию unwrapInner (), поскольку она не предоставляется по умолчанию.

$.fn.extend({
  unwrapInner: function(selector) {
      return this.each(function() {
          var t = this,
              c = $(t).children(selector);
          if (c.length === 1) {
              c.contents().appendTo(t);
              c.remove();
          }
      });
  },
  textWidth: function() {
    var self = $(this);
    $(this).wrapInner('<span id="text-width-calc"></span>');
    var width = $(this).find('#text-width-calc').width();
    $(this).unwrapInner();
    return width;
  }
});

+1 за .wrapInner. Как вы, наверное, знаете, работать с чистыми текстовыми элементами в jQuery - ад. Если есть какие-либо другие подходящие методы jQuery, сообщите мне. Мне пришлось прибегнуть к .get (0) .children, и это некрасиво.
Orwellophile

1

Расширение ответа @ philfreo:

Я добавил возможность проверки text-transform, так как такие вещи text-transform: uppercaseобычно делают текст шире.

$.fn.textWidth = function (text, font, transform) {
    if (!$.fn.textWidth.fakeEl) $.fn.textWidth.fakeEl = $('<span>').hide().appendTo(document.body);
    $.fn.textWidth.fakeEl.text(text || this.val() || this.text())
        .css('font', font || this.css('font'))
        .css('text-transform', transform || this.css('text-transform'));
    return $.fn.textWidth.fakeEl.width();
};

0
var calc = '<span style="display:none; margin:0 0 0 -999px">' + $('.move').text() + '</span>';

0

Вызовите getColumnWidth (), чтобы получить содержание текста. Это прекрасно работает.

someFile.css
.columnClass { 
    font-family: Verdana;
    font-size: 11px;
    font-weight: normal;
}


function getColumnWidth(columnClass,text) { 
    tempSpan = $('<span id="tempColumnWidth" class="'+columnClass+'" style="display:none">' + text + '</span>')
          .appendTo($('body'));
    columnWidth = tempSpan.width();
    tempSpan.remove();
return columnWidth;
}

Примечание: - Если вы хотите, чтобы встроенный .css передавал детали шрифта только в стиле.


0

Я изменил код Нико для своих нужд.

$.fn.textWidth = function(){
    var self = $(this),
        children = self.contents(),
        calculator = $('<span style="white-space:nowrap;" />'),
        width;

    children.wrap(calculator);
    width = children.parent().width(); // parent = the calculator wrapper
    children.unwrap();
    return width;
};

Я использую .contents (), поскольку .children () не возвращает текстовые узлы, которые мне нужны. Я также обнаружил, что на возвращаемую ширину влияет ширина области просмотра, которая вызвала перенос, поэтому я использую white-space: nowrap; чтобы получить правильную ширину независимо от ширины области просмотра.


0
$.fn.textWidth = function(){
        var w = $('body').append($('<span stlye="display:none;" id="textWidth"/>')).find('#textWidth').html($(this).html()[0]).width();
        $('#textWidth').remove();
        console.log(w);
        return w;
    };

почти один лайнер. Дает вам знак первого символа


0

Я не смог заставить ни одно из перечисленных решений работать на 100%, поэтому придумал этот гибрид , основанный на идеях от @chmurson (который, в свою очередь, был основан на @Okamera), а также от @philfreo:

(function ($)
{
    var calc;
    $.fn.textWidth = function ()
    {
        // Only create the dummy element once
        calc = calc || $('<span>').css('font', this.css('font')).css({'font-size': this.css('font-size'), display: 'none', 'white-space': 'nowrap' }).appendTo('body');
        var width = calc.html(this.html()).width();
        // Empty out the content until next time - not needed, but cleaner
        calc.empty();
        return width;
    };
})(jQuery);

Ноты:

  • this внутри метода расширения jQuery уже есть объект jQuery, поэтому нет необходимости во всех дополнительных $(this) которые есть во многих примерах.
  • Он только один раз добавляет фиктивный элемент в тело и использует его повторно.
  • Вы также должны указать white-space: nowrap, чтобы убедиться, что он измеряется как одна строка (а не перенос строки на основе других стилей страницы).
  • Я не мог заставить это работать, используя fontодин, и мне также пришлось явно копировать font-size. Пока не уверен, почему (все еще исследую).
  • Это не поддерживает поля ввода таким образом @philfreo.

0

Иногда нужно дополнительно измерить высоту и не только текст , но и ширину HTML . Я взял ответ @philfreo и сделал его более гибким и полезным:

function htmlDimensions(html, font) {
  if (!htmlDimensions.dummyEl) {
    htmlDimensions.dummyEl = $('<div>').hide().appendTo(document.body);
  }
  htmlDimensions.dummyEl.html(html).css('font', font);
  return {
    height: htmlDimensions.dummyEl.height(),
    width: htmlDimensions.dummyEl.width()
  };
}

0

ширина текста может быть разной для разных родителей, например, если вы добавляете текст в тег h1, он будет шире, чем div или label, поэтому мое решение вроде этого:

<h1 id="header1">

</h1>

alert(calcTextWidth("bir iki", $("#header1")));

function calcTextWidth(text, parentElem){
    var Elem = $("<label></label>").css("display", "none").text(text);
    parentElem.append(Elem);
  var width = Elem.width();
  Elem.remove();
    return width;
}

0

У меня были проблемы с решениями типа @ rune-kaagaard для больших объемов текста. Я обнаружил это:

$.fn.textWidth = function() {
	var width = 0;
	var calc = '<span style="display: block; width: 100%; overflow-y: scroll; white-space: nowrap;" class="textwidth"><span>' + $(this).html() + '</span></span>';
	$('body').append(calc);
	var last = $('body').find('span.textwidth:last');
	if (last) {
			var lastcontent = last.find('span');
			width = lastcontent.width();
			last.remove();
	}
	return width;
};

JSFiddle GitHub


-1

я думаю, тебе стоит использовать $('.calltoaction').val;

Кроме того, я бы использовал id (#) вместо класса для этого ... если у вас есть несколько таких классов, как бы он с этим справился?


Да, в документе их несколько. Почему вы предлагаете идентификатор?
Dom
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.