Textbreite berechnen

101

Ich versuche, die Textbreite mit jQuery zu berechnen. Ich bin mir nicht sicher was, aber ich mache definitiv etwas falsch.

Also, hier ist der Code:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);
Dom
quelle
Inwiefern funktioniert dieser Code nicht? Was muss es anders machen?
Sixten Otto

Antworten:

142

Das hat bei mir besser funktioniert:

$.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;
};
Rune Kaagaard
quelle
4
+1 - Dies misst wirklich den Text, nicht nur das enthaltende Blockelement wie die Lösung von brainreavis.
Ben
Glatt. +1. Es sieht so aus, als ob Ihnen in der dritten Zeile danach '</span>'ein Semikolon fehlt , obwohl es keinen Unterschied zu machen scheint (mit oder ohne FF9).
Shmeeps
21
Seien Sie jedoch vorsichtig ... Diese Methode hebt alle Ereignisse für untergeordnete Elemente auf.
Brianreavis
Ich habe versucht, diese Funktion auf verschiedene Arten zu verwenden, aber sie gibt immer wieder null zurück. Könnte jemand bitte die Syntax für die tatsächliche Verwendung dieser Funktion posten? Führe ich die Funktion .textWidth () für ein jQuery-Objekt aus? Übergebe ich Text an diese Funktion? Führe ich die Funktion als jQuery-Funktion aus (dh $ .textWidth (jqObject)? Weil keine dieser Optionen zu funktionieren scheint. Danke ...
moosefetcher
2
@moosefetcher würden Sie $ (Selektor) .textWidth () tun; Schauen Sie hier learn.jquery.com/plugins/basic-plugin-creation/…
uesports135
89

Hier ist eine Funktion, die besser ist als andere, weil

  1. es ist kürzer
  2. es funktioniert , wenn ein Übergang <input>, <span>oder "string".
  3. Für häufige Anwendungen ist es schneller, da ein vorhandenes DOM-Element wiederverwendet wird.

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();
};
Philfreo
quelle
1
Beeindruckend! Pure Großartigkeit!
Michel Triana
3
Tolle Lösung, sollte Antwort akzeptiert werden, denke ich! Danke Kumpel!
Ilia Rostovtsev
Fantastico! Einfach und sauber.
Carey Estes
Dies ist zwar gut, behandelt aber keine Leerzeichen. In der Antwort von @ edsioufi finden Sie eine Verbesserung dieser Lösung.
Badgerspot
Wenn sich im Element versteckter Text befindet, wird Ihre Breite verzerrt. Um dies zu berücksichtigen, müssen Sie die ausgeblendeten Knoten entfernen, bevor Sie die Textbreite berechnen. Um die versteckten Knoten sicher zu entfernen, sollten Sie wahrscheinlich zuerst einen Klon erstellen und dort entfernen.
12.
36

Meine Lösung

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

Grundsätzlich eine Verbesserung gegenüber Runes, die nicht .htmlso leichtfertig genutzt wird

bevacqua
quelle
Von Ajarn Gerhard , der dies als Antwort gepostet hat: Dies funktioniert nicht in IE8, weil Sie eine /vor der schließenden Klammer des <span>Tags fehlen :calculator = $('<span style="display: inline-block;" />'),
Petr R.
1
Dies scheint null zurückzugeben, wenn sich unter dem zu messenden Element ein untergeordnetes Element befindet. Kann es ohne das untergeordnete Element funktionieren? Siehe jsfiddle.net/h22tj/41
Casper
+1 - Ich wusste nie, dass es ein Unwrap () gibt, das mir endlosen Kummer bereitet hat.
Orwellophile
In Chrome wird immer null zurückgegeben.
Smaragdhieu
12

Die textWidthin den Antworten angegebenen Funktionen, die a stringals Argument akzeptieren, berücksichtigen keine führenden und nachfolgenden Leerzeichen (diese werden nicht im Dummy-Container gerendert). Sie funktionieren auch nicht, wenn der Text ein HTML-Markup enthält (eine Unterzeichenfolge <br>erzeugt keine Ausgabe und &nbsp;gibt die Länge eines Leerzeichens zurück).

Dies ist nur ein Problem für die textWidthFunktionen, die a akzeptieren string, denn wenn ein DOM-Element angegeben ist und .html()auf das Element aufgerufen wird, besteht wahrscheinlich keine Notwendigkeit, dies für einen solchen Anwendungsfall zu beheben.

Wenn Sie beispielsweise die Breite des Texts berechnen, um die Breite eines Textelements inputwährend der Benutzertypen dynamisch zu ändern (mein aktueller Anwendungsfall), möchten Sie wahrscheinlich führende und nachfolgende Leerzeichen durch &nbsp;die Zeichenfolge ersetzen und diese codieren zu html.

Ich habe die Lösung von philfreo verwendet. Hier ist eine Version davon, die dies behebt (mit Kommentaren zu Ergänzungen):

$.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();
};
edsioufi
quelle
Vielen Dank. Ihre Antwort ist am wertvollsten.
Vishal
1
Seltsamerweise hat es das nicht richtig kopiert, als ich es ausprobiert habe font-size. Ich musste hinzufügen, css('font-size'), this.css('font-size'))damit es funktioniert. Irgendwelche Ideen, warum fontallein dieser Wert nicht kopiert wird?
Gone Coding
@GoneCoding Wo haben Sie diese Extras hinzugefügt?
Webmagnete
@webmagnets: Gleiche Stelle wie die vorhandene .cssMethode, aber ich sehe, dass meine Klammern falsch sind. Sollte sein css('font-size', this.css('font-size')).
Gone Coding
11

Die Breitenfunktionen von jQuery können aufgrund inkonsistenter Boxmodelle etwas zwielichtig sein, wenn versucht wird, die Textbreite zu bestimmen. Der sichere Weg wäre, div in Ihr Element einzufügen, um die tatsächliche Textbreite zu bestimmen:

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

Um dieses Mini-Plugin zu verwenden, einfach:

$('.calltoaction').textWidth();
Brianreavis
quelle
1
Würde Ihnen dies nicht eher die Blockbreite als den Text geben?
Josh Rickard
-1 Dies scheint tatsächlich eher die Breite des Feldes als die Textbreite zu messen.
Nathan Arthur
1
Würde nicht einfach die Verwendung einer Spanne anstelle einer Div das Breitenproblem beheben? Wenn ja, dann ist diese Funktion etwas besser als die akzeptierte Antwort.
Josh
@ Josh: Wenn Sie es durch ein ersetzen, erhalten spanSie nur Null. Versuchte diese Lösung auf einem H2, wo übergeordnete Elemente Überlauf versteckt haben, und ich bekomme nur die abgeschnittene Länge des Textes. Vielleicht würde eine Erklärung, wie dies funktionieren soll, dazu beitragen, dass es besser funktioniert?
Gone Coding
8

Ich fand, dass diese Lösung gut funktioniert und die Ursprungsschriftart vor der Größenänderung erbt:

$.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;
}
Vince Spicer
quelle
1
Am Ende habe ich das benutzt, aber hinzugefügt org.css("font-weight"). Ich würde auch sagen, dass der if(!text)Teil nicht intuitiv ist. Wenn ich zB verwende jQuery("#someContainer").textWidth("Lorem ipsum"), möchte ich die Textbreite von "Lorem ipsum" wissen, wenn es in diesem bestimmten Container angewendet wird.
Schlecht
8

Weder Runes noch Brains arbeiteten für mich, falls das Element, das den Text enthielt, eine feste Breite hatte. Ich habe etwas Ähnliches wie Okamera gemacht. Es werden weniger Selektoren verwendet.

BEARBEITEN: Es wird wahrscheinlich nicht für Elemente funktionieren, die relative verwenden font-size, da der folgende Code ein htmlCalcElement einfügt , bodywodurch die Informationen über die Elternbeziehung verloren gehen.

$.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;
};
chmurson
quelle
Dies war die beste Lösung für mich mit IE8-Unterstützung und wird dabei keine Bindungen an das Element lösen! Vielen Dank.
Ouija
Hinweis: In einer jQuery-Erweiterungsmethode thisist bereits ein jQuery-Objekt vorhanden, daher $(this)ist es redundant.
Gone Coding
Dies hat bei mir falsch funktioniert, da die berechnete Breite zu klein ist. Die akzeptierte Antwort funktionierte korrekt
PandaWood
5

Wenn Sie versuchen, dies mit Text in einem Auswahlfeld zu tun, oder wenn diese beiden nicht funktionieren, versuchen Sie stattdessen Folgendes:

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

oder

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

Wenn Sie zuerst den Text abrufen möchten

okamera
quelle
4

Die Sache, die Sie falsch machen, ist, dass Sie eine Methode für cTxt aufrufen, die eine einfache Zeichenfolge und kein jQuery-Objekt ist. cTxt ist wirklich der enthaltene Text.

Juraj Blahunka
quelle
2

Leichte Änderung an Nico, da .children () eine leere Menge zurückgibt, wenn wir auf ein Textelement wie h1 oder p verweisen . Also verwenden wir stattdessen .contents () und dies anstelle von $ (this), da wir eine Methode für ein jQuery-Objekt erstellen.

$.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;
    };
309designer
quelle
1

Nachdem ich zwei Tage lang einem Geist nachgejagt hatte, um herauszufinden, warum die Breite eines Textes falsch war, wurde mir klar, dass Leerzeichen in der Textzeichenfolge die Breitenberechnung stoppen würden.

Ein weiterer Tipp ist, zu überprüfen, ob die Leerzeichen Probleme verursachen. verwenden

&nbsp;

nicht unterbrechender Raum und sehen Sie, ob dies das Problem behebt.

Die anderen Funktionen, die die Leute vorgeschlagen hatten, funktionierten ebenfalls gut, aber es waren die Leerzeichen, die Probleme verursachten.

Zonabi
quelle
Fügen Sie white-space: nowrapdas Inline-CSS nur vorübergehend hinzu , um dies zu vermeiden.
Gone Coding
1

Wenn Sie versuchen, die Breite einer Mischung aus Textknoten und Elementen innerhalb eines bestimmten Elements zu bestimmen, müssen Sie den gesamten Inhalt mit wrapInner () umbrechen , die Breite berechnen und dann den Inhalt auspacken.

* Hinweis: Sie müssen jQuery auch erweitern, um eine unwrapInner () -Funktion hinzuzufügen, da diese nicht standardmäßig bereitgestellt wird.

$.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;
  }
});
trip41
quelle
+1 für .wrapInner. Wie Sie wahrscheinlich wissen, ist der Umgang mit reinen Textelementen in jQuery die Hölle. Wenn andere jQuery-Methoden anwendbar sind, lassen Sie es mich bitte wissen. Ich musste auf .get (0) .children zurückgreifen und es ist nicht schön.
Orwellophile
1

Erweiterung der Antwort von @ philfreo:

Ich habe die Möglichkeit hinzugefügt, nach zu suchen text-transform, da Dinge wie text-transform: uppercasenormalerweise dazu neigen, den Text breiter zu machen.

$.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();
};
shaneparsons
quelle
0
var calc = '<span style="display:none; margin:0 0 0 -999px">' + $('.move').text() + '</span>';
Yura
quelle
0

Rufen Sie getColumnWidth () auf, um den Text abzurufen. Das funktioniert einwandfrei.

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

Hinweis: - Wenn Sie Inline-CSS möchten, übergeben Sie die Schriftdetails nur im Stil.

Arun Pratap Singh
quelle
0

Ich habe Nicos Code so geändert, dass er meinen Anforderungen entspricht.

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

Ich verwende .contents (), da .children () keine von mir benötigten Textknoten zurückgibt. Ich habe auch festgestellt, dass die zurückgegebene Breite durch die Breite des Ansichtsfensters beeinflusst wurde, was zu einem Umbruch führte. Daher verwende ich Leerzeichen: nowrap; um die richtige Breite unabhängig von der Breite des Ansichtsfensters zu erhalten.

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

fast ein Einzeiler. Gibt dir das mit des ersten Charakters

ceed
quelle
0

Ich konnte keine der aufgelisteten Lösungen zu 100% zum Laufen bringen und entwickelte diesen Hybrid , basierend auf Ideen von @chmurson (der wiederum auf @Okamera basierte) und auch von @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);

Anmerkungen:

  • thisIn einer jQuery-Erweiterungsmethode befindet sich bereits ein jQuery-Objekt, sodass nicht all das Extra benötigt wird $(this), das viele Beispiele haben.
  • Das Dummy-Element wird dem Körper nur einmal hinzugefügt und wiederverwendet.
  • Sie sollten auch angeben white-space: nowrap, nur um sicherzustellen, dass es als einzelne Zeile gemessen wird (und nicht als Zeilenumbruch basierend auf einem anderen Seitenstil).
  • Ich konnte dies nicht fontalleine zum Laufen bringen und musste auch explizit kopieren font-size. Ich weiß noch nicht warum (untersucht noch).
  • Auf diese Weise werden Eingabefelder nicht unterstützt @philfreo.
Codierung weg
quelle
0

Manchmal müssen Sie zusätzlich die Höhe und nicht nur den Text , sondern auch die HTML-Breite messen . Ich nahm die Antwort von @philfreo und machte sie flexibler und nützlicher:

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()
  };
}
Daniel Kmak
quelle
0

Die Textbreite kann für verschiedene Eltern unterschiedlich sein. Wenn Sie beispielsweise einen Text in das h1-Tag einfügen, ist dieser breiter als div oder label. Meine Lösung lautet also wie folgt:

<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;
}
Saeed Taran
quelle
0

Ich hatte Probleme mit Lösungen wie @ rune-kaagaard für große Textmengen. Ich habe folgendes entdeckt:

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

Peeto
quelle
-1

Ich denke, Sie sollten verwenden $('.calltoaction').val;

Außerdem würde ich dafür id (#) anstelle einer Klasse verwenden. Wenn Sie mehr als eine dieser Klassen haben, wie würde es damit umgehen?

Noam Smadja
quelle
Ja, es gibt mehr als eine im Dokument. Warum würden Sie einen Ausweis vorschlagen?
Dom