Обчислення ширини тексту


101

Я намагаюся обчислити ширину тексту за допомогою jQuery. Я не впевнений, що, але я обов'язково роблю щось не так.

Отже, ось код:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);

Отже, яким чином цей код не працює? Що потрібно робити інакше?
Sixten Otto

Відповіді:


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 - це дійсно вимірює текст, а не лише такий блоковий елемент, як рішення мозкового рішення.
Бен

Гладкий. +1. Схоже, після третього рядка вам не вистачає '</span>'напівкрапки, хоча це, здається, не має значення (працювали з FF9 або без нього).
shmeeps

21
Будьте уважні з цим, хоча ... цей метод відв'яже будь-які події на дочірніх елементах.
brianreavis

Я намагався використовувати цю функцію кількома способами, але вона повертається до нуля. Чи може хтось, будь ласка, опублікувати синтаксис про те, як реально використовується ця функція? Чи запускати я .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
Чудове рішення, я повинен прийняти відповідь, я думаю! Дякую, приятелю!
Ілля Ростовцев

Фантастико! Простий і чистий.
Carey Estes

Хоча це добре, це не обробляє місця. Дивіться відповідь @ edsioufi для удосконалення цього рішення.
Badgerspot

Якщо всередині елемента є прихований текст, то він перекривить вашу ширину. Щоб врахувати це, обов’язково видаліть приховані вузли перед обчисленням ширини тексту. Щоб безпечно видалити приховані вузли, вам, мабуть, слід спочатку зробити клон і зробити там видалення.
thoan

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так легко використовується


Автор Аджарн Герхард, який опублікував це як відповідь: Це не працює в IE8, тому що ви пропускаєте a /перед кінцевою дужкою <span>тегу:calculator = $('<span style="display: inline-block;" />'),
Петро Р.

1
Здається, повертається до нуля, якщо під елементом, який ви вимірюєте, є дочірній елемент. Чи можна змусити його працювати без дочірнього елемента? Дивіться jsfiddle.net/h22tj/41
Каспер

+1 - Я ніколи не знав, що відбулося розмотування (), що викликало в мене нескінченне горе.
Орвелофіл

Завжди повертає нуль у Chrome.
смарагдовий

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

Дякую. Ваша відповідь найцінніша.
Вішал

1
Як не дивно, коли я спробував цей, він не правильно скопіював font-size. Мені довелося додати, css('font-size'), this.css('font-size'))щоб він працював. Будь-які ідеї, чому б fontодин не скопіював це значення?
Пройшов кодування

@GoneCoding Де ви додали ці додаткові послуги?
webmagnets

@webmagnets: Те саме місце, що і в існуючому .cssметоді, але я бачу, що мої дужки неправильні. Повинно бути css('font-size', this.css('font-size')).
Пройшов кодування

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
Не вдалося б просто скористатися прольотом, а не дівом виправити проблему з шириною? Якщо так, то ця функція трохи краща за прийняту відповідь.
Джош

@Josh: Якщо ви заміните його на то, spanви просто отримаєте нуль. Спробував це рішення на тему H2, де батьківські елементи приховують переповнення, і я отримую лише усічену довжину тексту. Можливо, пояснення того, як це повинно працювати , допоможе зробити його краще?
Пройшов кодування

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

Ні Руна, ні Мозок не працювали на мене в тому випадку, коли елемент, який тримав текст, мав фіксовану ширину. Я зробив щось подібне до Окамери. Тут використовується менше селекторів.

EDIT: Це, ймовірно, не буде працювати для елементів, які використовують відносні 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)є надмірним.
Пройшло кодування

Це працювало неправильно для мене, оскільки обчислена ширина занадто мала. Прийнята відповідь спрацювала правильно
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), оскільки ми створюємо метод для об’єкта 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, щоб уникнути цього.
Пройшов кодування

1

Якщо ви намагаєтеся визначити ширину поєднання текстових вузлів та елементів всередині певного елемента, вам потрібно обернути весь вміст wrapInner () , обчислити ширину, а потім розгорнути вміст.

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

$.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) .для дітей, і це не дуже.
Орвелофіл

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 () не повертає текстові вузли, які мені були потрібні. Я також виявив, що на повернуту ширину впливала ширина вікна перегляду, яка викликала обгортання, тому я використовую пробіл: 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's, для великої кількості тексту. Я виявив це:

$.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 (#) замість класу для цього .. якщо у вас є більше одного з таких класів, як би це обробити?


Так, у документі є більше, ніж один. Чому б ти запропонував ідентифікатор?
Дом
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.