计算文本宽度

103

我正在尝试使用jQuery计算文本宽度。我不确定是什么问题,但肯定出现了错误。

这是我的代码:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);

那么,这段代码有什么问题?它需要做出哪些不同的改变呢? - Sixten Otto
22个回答

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的解决方案那样测量包含块元素。 - Ben
22
请注意...这种方法会解除子元素上的所有事件绑定。 - brianreavis
我已经尝试过多种方式使用这个函数,但它始终返回 null。请问有人能发布一下这个函数的实际使用语法吗?我是否需要在 jQuery 对象上运行 .textWidth() 函数?我是将文本传递给这个函数吗?我是作为 jQuery 函数运行这个函数的吗(例如 $.textWidth(jqObject))?因为这些选项中似乎没有一个可行的。谢谢… - moosefetcher
2
@moosefetcher 你可以使用 $(selector).textWidth(); 来实现。请参考这里 https://learn.jquery.com/plugins/basic-plugin-creation/#basic-plugin-authoring - uesports135
我会在 span 元素中添加 white-space: nowrap,否则如果文本因容器太小而换行,你将得到错误的结果。 - tocqueville
显示剩余3条评论

90

这是一个比其他发布的函数更好的函数,因为:

  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
哇!纯粹的令人惊叹! - Michel Triana
3
好的解决方案,应该接受为最佳答案,我认为!谢谢,朋友! - Ilia
太棒了!简单而干净。 - Carey Estes
Magic!能够优雅地处理不同字体大小。谢谢。 - geevee
太棒了!我稍微修改了一下。我只是使用调用函数的元素并获取该字体传递给span。这样可以避免传递字体本身。$.fn.widthOfTextInElement = function () { if (!$.fn.widthOfTextInElement.fakeEl) $.fn.widthOfTextInElement.fakeEl = $('<span>').hide().appendTo(document.body); $.fn.widthOfTextInElement.fakeEl.text($(this).text() || $(this).val()) .css('font', $(this).css("font")); return $.fn.widthOfTextInElement.fakeEl.width(); } - John Pasquet
显示剩余4条评论

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

基本上是对Rune的改进,不过不会轻易使用.html

Ajarn Gerhard发布的答案:在IE8中无法工作,因为您在<span>标签的结束括号之前缺少/calculator = $('<span style="display: inline-block;" />'), - Petr R.
1
如果您正在测量的元素下面有子元素,则此代码似乎会返回 null。它能否在没有子元素的情况下正常工作?请参阅 http://jsfiddle.net/h22tj/41/。 - Casper
+1 - 我从未知道有 unwrap(),这让我痛苦不堪。 - Orwellophile
在 Chrome 上它总是返回 null。 - emeraldhieu

12

提供的textWidth函数接受一个字符串作为参数,但不会考虑前导和尾随空格(这些在虚拟容器中不会被呈现)。此外,如果文本包含任何HTML标记(子字符串<br>将不会产生任何输出,&nbsp;将返回一个空格的长度),则它们也无法工作。

对于接受字符串的textWidth函数而言,这只是一个问题,因为如果给定DOM元素,并在该元素上调用.html(),那么可能没有必要为这种用例进行修复。

但是,例如,如果您正在计算文本的宽度以动态修改用户输入时文本输入元素的宽度(我的当前用例),则可能希望使用&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不能复制该值? - iCollect.it Ltd
@GoneCoding 你把那些额外的东西加在哪里了? - webmagnets
@webmagnets:与现有的.css方法相同的位置,但我看到我的括号是错误的。应该是css('font-size', this.css('font-size')) - iCollect.it Ltd

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
这不会给你块的宽度,而不是文本吗? - Josh Rickard
这确实似乎是测量盒子宽度而非文本宽度。 - Nathan Arthur
1
仅使用span而不是div是否可以解决宽度问题?如果是这样,那么这个函数比被接受的答案要好一些。 - Josh
@Josh:如果你用span替换它,你只会得到零。我在一个H2上尝试了这个解决方案,其中父元素有溢出隐藏,但我只得到了文本的截断长度。也许解释一下这个应该如何工作会更好地发挥它的作用? - iCollect.it Ltd

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都不能正常工作。我做了类似于Okamera的事情,使用了更少的选择器。

编辑: 对于使用相对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) 是多余的。 - iCollect.it Ltd
这对我而言行不通,因为计算出来的宽度太小了。被接受的答案是正确的。 - 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
稍微修改Nico的代码,因为.children()方法将返回一个空集合,如果我们引用的是文本元素,例如h1p。所以我们将使用.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;
    };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接