Calcolo della larghezza del testo


101

Sto cercando di calcolare la larghezza del testo usando jQuery. Non sono sicuro di cosa, ma sto decisamente facendo qualcosa di sbagliato.

Quindi, ecco il codice:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);

Allora, in che modo quel codice non funziona? Cosa deve fare diversamente?
Sixten Otto,

Risposte:


142

Questo ha funzionato meglio per me:

$.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: misura veramente il testo, non solo l'elemento del blocco contenitore come la soluzione di brainreavis.
Ben

Slick. +1. Sembra che manchi un punto e virgola sulla terza riga dopo '</span>', anche se non sembra fare differenza (ha funzionato con o senza di esso su FF9).
incontra il

21
Fai attenzione a questo però ... questo metodo svincolerà tutti gli eventi sugli elementi figlio.
brianreavis

Ho provato a utilizzare questa funzione in diversi modi, ma continua a restituire null. Qualcuno potrebbe inviare la sintassi per come questa funzione viene effettivamente utilizzata? Eseguo la funzione .textWidth () su un oggetto jQuery? Passo il testo a questa funzione? Eseguo la funzione come una funzione jQuery (cioè $ .textWidth (jqObject)? Perché nessuna di queste opzioni sembra funzionare. Grazie ...
moosefetcher

2
@moosefetcher faresti $ (selector) .textWidth (); Guarda qui learn.jquery.com/plugins/basic-plugin-creation/…
uesports135

89

Ecco una funzione che è migliore di altre pubblicate perché

  1. è più breve
  2. funziona quando si passa una <input>, <span>o "string".
  3. è più veloce per usi frequenti perché riutilizza un elemento DOM esistente.

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
Wow! Pura suggestione!
Michel Triana

3
Ottima soluzione, dovrebbe essere accettata la risposta, credo! Grazie amico!
Ilia Rostovtsev

Fantastico! Semplice e pulito.
Carey Estes

Anche se buono, questo non gestisce gli spazi. Vedi la risposta di @ edsioufi per un miglioramento di questa soluzione.
Badgerspot

Se c'è del testo nascosto all'interno dell'elemento, la tua larghezza sarà distorta. Per tenere conto di ciò, assicurati di rimuovere i nodi nascosti prima di calcolare la larghezza del testo. Per rimuovere in sicurezza i nodi nascosti, dovresti probabilmente creare prima un clone ed eseguire la rimozione lì.
thdoan

36

La mia soluzione

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

Fondamentalmente un miglioramento rispetto a Rune, che non usa .htmlcosì alla leggera


Di Ajarn Gerhard che ha pubblicato questo come risposta: Questo non funziona in IE8 perché ti manca un /prima della parentesi di chiusura del <span>tag:calculator = $('<span style="display: inline-block;" />'),
Petr R.

1
Questo sembra restituire null se c'è un elemento figlio sotto l'elemento che stai misurando. Può essere fatto funzionare senza l'elemento figlio? Vedi jsfiddle.net/h22tj/41
Casper

+1 - Non ho mai saputo che ci fosse un wrap (), che mi ha causato un dolore senza fine.
Orwellophile

Restituisce sempre null su Chrome.
emeraldhieu

12

Le textWidthfunzioni fornite nelle risposte e che accettano un stringcome argomento non tengono conto degli spazi bianchi iniziali e finali (quelli non vengono visualizzati nel contenitore fittizio). Inoltre, non funzioneranno se il testo contiene markup html (una sottostringa <br>non produrrà alcun output e &nbsp;restituirà la lunghezza di uno spazio).

Questo è solo un problema per le textWidthfunzioni che accettano a string, perché se viene fornito un elemento DOM e .html()viene richiamato sull'elemento, probabilmente non è necessario risolverlo per questo caso d'uso.

Ma se, ad esempio, stai calcolando la larghezza del testo per modificare dinamicamente la larghezza di un inputelemento di testo mentre l'utente digita (il mio caso d'uso corrente), probabilmente vorrai sostituire gli spazi iniziali e finali con &nbsp;e codificare la stringa in html.

Ho usato la soluzione di philfreo, quindi ecco una versione che risolve questo problema (con commenti sulle aggiunte):

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

Grazie. La tua risposta è molto preziosa.
Vishal

1
Stranamente, quando ho provato questo, non ha copiato correttamente il file font-size. Ho dovuto aggiungere css('font-size'), this.css('font-size'))perché funzionasse. Qualche idea sul perché fontda solo non copia quel valore?
Gone Coding

@GoneCoding Dove hai aggiunto questi extra?
webmagnets

@webmagnets: stesso posto del .cssmetodo esistente , ma vedo che le mie parentesi sono sbagliate. Dovrebbe essere css('font-size', this.css('font-size')).
Gone Coding

11

Le funzioni di larghezza di jQuery possono essere un po 'ombreggiate quando si cerca di determinare la larghezza del testo a causa di modelli di box incoerenti. Il modo sicuro sarebbe iniettare div all'interno del tuo elemento per determinare la larghezza effettiva del testo:

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

Per utilizzare questo mini plugin, semplicemente:

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

1
Questo non ti darebbe la larghezza del blocco piuttosto che il testo?
Josh Rickard

-1 Questo sembra effettivamente misurare la larghezza del riquadro piuttosto che la larghezza del testo.
Nathan Arthur

1
L'uso di un intervallo invece di un div non risolverebbe il problema della larghezza? In tal caso, questa funzione è leggermente migliore della risposta accettata.
Josh

@ Josh: se lo sostituisci con un spanottieni zero. H2Ho provato questa soluzione su un , in cui gli elementi principali hanno un overflow nascosto e ottengo solo la lunghezza troncata del testo. Forse una spiegazione di come dovrebbe funzionare aiuterebbe a farlo funzionare meglio?
Gone Coding

8

Ho trovato che questa soluzione funziona bene ed eredita il carattere di origine prima del dimensionamento:

$.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
Ho finito per usare questo, ma ho aggiunto org.css("font-weight"). Inoltre, direi che la if(!text)parte non è intuitiva. Se uso, ad esempio jQuery("#someContainer").textWidth("Lorem ipsum"), vorrei conoscere la larghezza del testo di "Lorem ipsum" quando applicato in quel particolare contenitore.
Sleavely

8

Né Rune né Brain funzionavano per me nel caso in cui l'elemento che conteneva il testo avesse una larghezza fissa. Ho fatto qualcosa di simile a Okamera. Utilizza meno selettori.

EDIT: Probabilmente non funzionerà per gli elementi che usano relativo font-size, poiché il codice seguente inserisce l' htmlCalcelemento in bodyquindi perde le informazioni sulla relazione dei genitori.

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

Questa è stata la soluzione migliore per me con il supporto di IE8 e non interromperà alcun vincolo all'elemento nel processo! Grazie.
ouija

nota: in un metodo di estensione jQuery, thisè già un oggetto jQuery quindi $(this)è ridondante.
Gone Coding

Questo ha funzionato male per me, in quanto la larghezza calcolata è troppo piccola. La risposta accettata ha funzionato correttamente
PandaWood

5

Se stai cercando di farlo con il testo in una casella di selezione o se quei due non funzionano, prova invece questo:

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

o

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

se vuoi prendere prima il testo


4

il fatto, stai sbagliando, che stai chiamando un metodo su cTxt, che è una semplice stringa e non un oggetto jQuery. cTxt è davvero il testo contenuto.


2

Leggera modifica a quella di Nico, poiché .children () restituirà un set vuoto se si fa riferimento a un elemento di testo come h1 o p . Quindi useremo .contents () invece, e useremo questo invece di $ (this) poiché stiamo creando un metodo su un oggetto 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

dopo aver inseguito un fantasma per due giorni, cercando di capire perché la larghezza di un testo non fosse corretta, mi sono reso conto che era a causa degli spazi bianchi nella stringa di testo che avrebbero interrotto il calcolo della larghezza.

quindi, un altro suggerimento è controllare se gli spazi bianchi stanno causando problemi. uso

&nbsp;

spazio unificatore e vedere se questo lo risolve.

anche le altre funzioni suggerite dalle persone funzionano bene, ma sono gli spazi bianchi a causare problemi.


Basta aggiungere temporaneamente white-space: nowrapal CSS inline per evitarlo.
Gone Coding

1

Se stai cercando di determinare la larghezza di un mix di nodi di testo ed elementi all'interno di un dato elemento, devi avvolgere tutti i contenuti con wrapInner () , calcolare la larghezza e quindi scartare il contenuto.

* Nota: sarà inoltre necessario estendere jQuery per aggiungere una funzione unfrapInner () poiché non è fornita di default.

$.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 per .wrapInner. Come probabilmente saprai, trattare con elementi di testo puro in jQuery è un inferno. Se ci sono altri metodi jQuery applicabili, fammelo sapere. Ho dovuto ricorrere a .get (0) .children e non è carino.
Orwellophile

1

Espandendo la risposta di @ philfreo:

Ho aggiunto la possibilità di controllare text-transform, poiché cose come di text-transform: uppercasesolito tendono a rendere il testo più ampio.

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

Chiama getColumnWidth () per ottenere il con del testo. Funziona perfettamente bene.

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

Nota: - Se vuoi .css inline passa i dettagli del carattere solo in stile.


0

Ho modificato il codice di Nico per adattarlo alle mie esigenze.

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

Sto usando .contents () poiché .children () non restituisce i nodi di testo di cui avevo bisogno. Ho anche scoperto che la larghezza restituita era influenzata dalla larghezza del viewport che causava il wrapping, quindi sto usando lo spazio bianco: nowrap; per ottenere la larghezza corretta indipendentemente dalla larghezza del viewport.


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

quasi una linea. Ti dà il con del primo carattere


0

Non sono riuscito a far funzionare al 100% nessuna delle soluzioni elencate, quindi ho ideato questo ibrido , basato sulle idee di @chmurson (che a sua volta era basato su @Okamera) e anche di @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);

Appunti:

  • thisall'interno di un metodo di estensione jQuery c'è già un oggetto jQuery, quindi non c'è bisogno di tutti gli extra $(this)che hanno molti esempi.
  • Aggiunge l'elemento fittizio al corpo una sola volta e lo riutilizza.
  • Dovresti anche specificare white-space: nowrap, solo per assicurarti che lo misuri come una singola riga (e non a capo automatico basato su altri stili di pagina).
  • Non sono riuscito a farlo funzionare da fontsolo e ho anche dovuto copiare esplicitamente font-size. Non sono ancora sicuro del perché (sto ancora indagando).
  • Questo non supporta i campi di input in questo modo @philfreo.

0

A volte è necessario misurare anche l' altezza e non solo il testo , ma anche la larghezza dell'HTML . Ho preso la risposta di @philfreo e l'ho resa più flessibile e utile:

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

la larghezza del testo può essere diversa per i diversi genitori, ad esempio se aggiungi un testo nel tag h1 sarà più largo di div o label, quindi la mia soluzione come questa:

<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

Ho avuto problemi con soluzioni come @ rune-kaagaard per grandi quantità di testo. Ho scoperto questo:

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

penso che dovresti usare $('.calltoaction').val;

inoltre, userei id (#) invece di una classe per questo .. se tu avessi più di una di queste classi, come lo gestiresti?


Sì, ce n'è più di uno nel documento. Perché suggeriresti id?
Dom
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.