Metin genişliğini hesaplama


101

JQuery kullanarak metin genişliğini hesaplamaya çalışıyorum. Ne olduğundan emin değilim ama kesinlikle yanlış bir şey yapıyorum.

İşte kod:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);

Peki bu kod ne şekilde çalışmıyor? Neyi farklı yapması gerekiyor?
Sixten Otto

Yanıtlar:


142

Bu benim için daha iyi çalıştı:

$.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 - bu, sadece brainreavis'in çözümü gibi içeren blok unsurunu değil, metni gerçekten ölçer.
Ben

Kaygan. +1. Görünüşe göre üçüncü satırda '</span>'noktalı virgül eksik görünüyor , ancak bir fark yaratmıyor gibi görünüyor (FF9'da onunla veya onsuz çalıştı).
33'te shmeeps

21
Yine de buna dikkat edin ... bu yöntem alt öğelerdeki herhangi bir olayı çözecektir.
brianreavis

Bu işlevi çeşitli şekillerde kullanmayı denedim, ancak boş dönmeye devam ediyor. Birisi bu işlevin gerçekte nasıl kullanıldığına dair sözdizimini gönderebilir mi? .TextWidth () işlevini bir jQuery nesnesinde çalıştırmalı mıyım? Bu işleve metin iletir miyim? Bu işlevi bir jQuery işlevi olarak çalıştırıyor muyum (yani $ .textWidth (jqObject)? Çünkü bu seçeneklerin hiçbiri işe yaramıyor. Teşekkürler ...
moosefetcher

2
@moosefetcher yaparsınız $ (seçici) .textWidth (); Buraya bakın learn.jquery.com/plugins/basic-plugin-creation/…
uesports135

89

İşte diğerlerinden daha iyi olan bir işlev çünkü

  1. daha kısa
  2. Bir geçerken çalışır <input>, <span>ya da "string".
  3. mevcut bir DOM öğesini yeniden kullandığı için sık kullanım için daha hızlıdır.

Demo: 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
Vaov! Saf müthiş!
Michel Triana

3
Harika çözüm, cevap kabul edilmeli, bence! Teşekkürler dostum!
Ilia Rostovtsev

Fantastico! Basit ve temiz.
Carey Estes

İyi olsa da, bu boşluklarla başa çıkmaz. Bu çözüme yönelik bir iyileştirme için @ edsioufi'nin yanıtına bakın.
Badgerspot

Öğenin içinde gizli metin varsa, genişliğinizi çarpıtır. Bunu hesaba katmak için, metin genişliğini hesaplamadan önce gizli düğümleri kaldırdığınızdan emin olun. Gizli düğümleri güvenli bir şekilde kaldırmak için, muhtemelen önce bir klon yapmalı ve kaldırmayı orada yapmalısınız.
thdoan

36

Çözümüm

$.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;
};

Temelde Rune bitti bir gelişme olduğunu kullanmaz .htmlbu yüzden hafifçe


By Ajarn Gerhard : cevap olarak bu yayınlanmıştır Eksik çünkü IE8 çalışan bu değil /kapanış parantez önce <span>: tagcalculator = $('<span style="display: inline-block;" />'),
Petr R.

1
Ölçtüğünüz öğenin altında alt öğe varsa, bu boş döndürüyor gibi görünüyor. Alt öğe olmadan çalıştırılabilir mi? Bkz jsfiddle.net/h22tj/41
Casper

+1 - Sonsuz kedere neden olan bir paket açma () olduğunu bilmiyordum.
Orwellophile

Chrome'da her zaman null döndürür.
emeraldhieu

12

textWidthCevap sağlanır ve işlevleri bir kabul string, boşluk, ön ve arka için hesap değil, bağımsız değişken (o kukla kapta işlenmez) elde edilir. Ayrıca, metin herhangi bir html biçimlendirmesi içeriyorsa çalışmazlar (bir alt dizge <br>herhangi bir çıktı üretmez ve &nbsp;bir boşluk uzunluğunu döndürür).

Bu yalnızca textWidtha'yı kabul eden işlevler için bir sorundur string, çünkü bir DOM öğesi verilmişse ve .html()öğeye çağrılmışsa, bu tür bir kullanım durumu için muhtemelen bunu düzeltmeye gerek yoktur.

Ancak, örneğin, kullanıcı yazarken bir metin inputöğesinin genişliğini dinamik olarak değiştirmek için metnin genişliğini hesaplıyorsanız (benim mevcut kullanım durumum), muhtemelen baştaki ve sondaki boşlukları &nbsp;dizeyle değiştirip kodlamak isteyeceksiniz. html için.

Philfreo'nun çözümünü kullandım, bu yüzden işte bunu düzelten bir sürümü var (eklemelerle ilgili yorumlarla):

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

Teşekkürler. Cevabınız çok değerlidir.
Vishal

1
İşin garibi, bunu denediğimde font-size,. css('font-size'), this.css('font-size'))Çalışması için eklemek zorunda kaldım . Neden fonttek başına bu değeri kopyalamadığına dair bir fikrin var mı?
Kodlamaya Gitti

@GoneCoding Bu ekstraları nereye eklediniz?
webmagnets

@webmagnets: Mevcut .cssyöntemle aynı yerde , ancak parantezlerimin yanlış olduğunu görüyorum. Olmalı css('font-size', this.css('font-size')).
Kodlama gitti

11

Tutarsız kutu modelleri nedeniyle metin genişliğini belirlemeye çalışırken jQuery'nin genişlik işlevleri biraz gölgeli olabilir. Kesin olan yol, gerçek metin genişliğini belirlemek için öğenizin içine div enjekte etmektir:

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

Bu mini eklentiyi kullanmak için basitçe:

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

1
Bu size metinden ziyade blok genişliğini vermez mi?
Josh Rickard

-1 Bu aslında metin genişliğinden ziyade kutunun genişliğini ölçüyor gibi görünüyor.
Nathan Arthur

1
Div yerine bir yayılma kullanmak genişlik sorununu çözmez mi? Eğer öyleyse, bu fonksiyon kabul edilen cevaptan biraz daha iyidir.
Josh

@ Josh: Eğer onu bir ile değiştirirseniz, spansadece sıfır elde edersiniz. Bu çözümü, H2üst öğelerin gizlendiği bir yerde denedim ve yalnızca metnin kesilmiş uzunluğunu elde ettim. Belki de bunun nasıl çalışacağına dair bir açıklama daha iyi çalışmasına yardımcı olabilir mi?
Kodlama Gone

8

Bu çözümün iyi çalıştığını ve boyutlandırmadan önce kaynak yazı tipini miras aldığını buldum:

$.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
Bunu kullandım ama ekledim org.css("font-weight"). Ayrıca, if(!text)bölümün sezgisel olmadığını söyleyebilirim . Örneğin kullanırsam jQuery("#someContainer").textWidth("Lorem ipsum"), söz konusu konteynere uygulandığında "Lorem ipsum" un metin genişliğini bilmek isterim.
Alçakgönüllü

8

Metni tutan öğenin sabit genişliğe sahip olması durumunda ne Rune ne de Brain benim için çalışmıyordu. Okamera'ya benzer bir şey yaptım. Daha az seçici kullanır.

DÜZENLEME: Muhtemelen göreli kullanan elemanlar için çalışmayacaktır font-size, çünkü aşağıdaki kod htmlCalceleman eklediği bodyiçin ebeveyn ilişkisi hakkındaki bilgileri kaybedecektir.

$.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;
};

Bu, IE8 desteğiyle benim için en iyi çözümdü ve bu süreçte öğeye olan herhangi bir bağlantıyı bozmayacak! Teşekkürler.
ouija

not: Bir jQuery genişletme yönteminde, thiszaten bir jQuery nesnesi $(this)olduğundan fazlalıktır.
Kodlamaya Gitti

Hesaplanan genişliğin çok küçük olması nedeniyle bu benim için yanlış çalıştı. Kabul edilen cevap doğru çalıştı
PandaWood

5

Bunu bir seçim kutusundaki metinle yapmaya çalışıyorsanız veya bu ikisi çalışmıyorsa, bunun yerine şunu deneyin:

$.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;
};

veya

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

önce metni almak istersen


4

yanlış yapıyorsunuz, basit bir dize olan ve bir jQuery nesnesi olmayan cTxt'de bir yöntem çağırıyorsunuz. cTxt gerçekten içerilen metindir.


2

.Children (), h1 veya p gibi bir metin öğesine başvuruyorsak boş bir küme döndüreceğinden, Nico'ya küçük bir değişiklik . Onun yerine .contents () kullanacağız ve bunu $ (this) yerine kullanacağız çünkü jQuery nesnesinde bir metot oluşturuyoruz.

$.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

İki gün boyunca bir hayaletin peşinden koşarak, bir metnin genişliğinin neden yanlış olduğunu anlamaya çalıştıktan sonra, metin dizesindeki beyaz boşlukların genişlik hesaplamasını durduracağını fark ettim.

Bu nedenle, başka bir ipucu, boşlukların sorunlara neden olup olmadığını kontrol etmektir. kullanım

&nbsp;

bölünmeyen boşluk ve bunun düzeltip düzeltmediğine bakın.

İnsanların önerdiği diğer işlevler de iyi çalışıyordu, ancak sorun yaratan beyaz boşluklardı.


Bundan white-space: nowrapkaçınmak için yalnızca geçici olarak satır içi CSS'ye ekleyin .
Kodlama Gitti

1

Belirli bir öğe içindeki metin düğümleri ve öğelerin karışımının genişliğini belirlemeye çalışıyorsanız, tüm içeriği wrapInner () ile sarmalısınız. , genişliği hesaplamanız ve ardından .

* Not: Ayrıca, varsayılan olarak sağlanmadığından, bir wrapsInner () işlevi eklemek için jQuery'yi genişletmeniz gerekecektir.

$.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;
  }
});

.WrapInner için +1. Muhtemelen bildiğiniz gibi, jQuery'de saf metin öğeleriyle uğraşmak cehennemdir. Uygulanabilen başka jQuery yöntemleri varsa lütfen bana bildirin. .Get (0) .children'a başvurmak zorunda kaldım ve bu hiç hoş değil.
Orwellophile

1

@ Philfreo'nun cevabını genişleterek:

Bu tür text-transformşeyler text-transform: uppercasegenellikle metni daha geniş yapma eğiliminde olduğundan , kontrol etme yeteneği ekledim .

$.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

Metni almak için getColumnWidth () çağırın. Bu gayet iyi çalışıyor.

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

Not: - Satır içi .css'nin font ayrıntılarını yalnızca stilde iletmesini istiyorsanız.


0

Nico'nun kodunu ihtiyaçlarımı karşılayacak şekilde değiştirdim.

$.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;
};

Kullandığım .contents () Ben gerekli metin düğümleri dönmez .Children olarak (). Ayrıca döndürülen genişliğin, kaydırmaya neden olan görüntü alanı genişliğinden etkilendiğini buldum, bu nedenle beyaz boşluk kullanıyorum: nowrap; görüntü alanı genişliğinden bağımsız olarak doğru genişliği elde etmek için.


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

neredeyse bir astar. Size ilk karakteri verir


0

% 100 işe yarayacak şekilde listelenen çözümlerden hiçbirini alamadım, bu nedenle , @chmurson'dan (@Okamera'ya dayanıyordu) ve ayrıca @filfreo'dan gelen fikirlere dayanarak bu hibrit ile geldim:

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

Notlar:

  • this bir jQuery genişletme yönteminin içinde zaten bir jQuery nesnesi olduğundan, tüm fazlalıklara gerek yoktur. $(this) birçok örneğin sahip .
  • Kukla öğeyi vücuda yalnızca bir kez ekler ve yeniden kullanır.
  • Ayrıca white-space: nowrap, tek bir satır olarak ölçüldüğünden emin olmak için de belirtmelisiniz (ve diğer sayfa stiline göre satır kaydırmayı değil).
  • Bunu fonttek başıma kullanmak için yapamadım ve açıkça kopyalamak zorunda kaldım font-size. Henüz neden olduğundan emin değilim (hala araştırıyor).
  • Bu , giriş alanlarını bu şekilde desteklemez @philfreo.

0

Bazen de ayrıca ölçmek için gereken yükseklik ve sadece metin değil, aynı zamanda, HTML genişliği . @Filfreo cevabını aldım ve daha esnek ve kullanışlı hale getirdim:

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

metin genişliği farklı ebeveynler için farklı olabilir, örneğin h1 etiketine bir metin eklerseniz, div veya etiketten daha geniş olacaktır, dolayısıyla benim çözümüm şöyle:

<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

Büyük miktarda metin için @ rune-kaagaard's gibi çözümlerle sorun yaşadım. Bunu keşfettim:

$.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

bence kullanmalısın $('.calltoaction').val;

ayrıca, bunun için bir sınıf yerine id (#) kullanırdım .. eğer böyle sınıflardan birden fazlasına sahipseniz, bunu nasıl idare ederdi?


Evet, belgede birden fazla var. Neden kimliği öneriyorsun?
Dom
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.