Tính toán chiều rộng văn bản


101

Tôi đang cố gắng tính toán chiều rộng văn bản bằng jQuery. Tôi không chắc điều gì, nhưng chắc chắn là tôi đang làm gì đó sai.

Vì vậy, đây là mã:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);

Vì vậy, theo cách nào mà mã đó không hoạt động? Nó cần làm gì khác đi?
Sixten Otto

Câu trả lời:


142

Điều này làm việc tốt hơn cho tôi:

$.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 - điều này thực sự đo lường văn bản, không chỉ là phần tử khối chứa như giải pháp của brainreavis.
Ben

Bóng mượt. +1. Có vẻ như bạn đang thiếu dấu chấm phẩy ở dòng thứ ba sau '</span>', mặc dù nó dường như không tạo ra sự khác biệt (hoạt động với hoặc không có trên FF9).
shmeeps

21
Hãy cẩn thận với điều này mặc dù ... phương pháp này sẽ hủy liên kết bất kỳ sự kiện nào trên các phần tử con.
brianreavis

Tôi đã cố gắng sử dụng hàm này theo một số cách, nhưng nó vẫn tiếp tục trả về null. Ai đó có thể vui lòng đăng cú pháp cho cách chức năng này thực sự được sử dụng? Tôi có chạy hàm .textWidth () trên đối tượng jQuery không? Tôi có chuyển văn bản vào chức năng này không? Tôi chạy các chức năng như một hàm jQuery (tức là $ .textWidth (jqObject) Bởi vì không ai trong số các lựa chọn này dường như làm việc Cảm ơn ...?.
moosefetcher

2
@moosefetcher bạn sẽ thực hiện $ (selector) .textWidth (); Hãy xem tại đây learning.jquery.com/plugins/basic-plugin-creation/…
uesports135

89

Đây là một chức năng tốt hơn những chức năng khác được đăng bởi vì

  1. nó ngắn hơn
  2. nó hoạt động khi đi qua một <input>, <span>hoặc "string".
  3. nó nhanh hơn khi sử dụng thường xuyên vì nó sử dụng lại phần tử DOM hiện có.

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
Chà! Sự tuyệt vời thuần túy!
Michel Triana,

3
Giải pháp tuyệt vời, nên được chấp nhận câu trả lời, tôi nghĩ! Cảm ơn, anh bạn!
Ilia Rostovtsev

Fantastico! Đơn giản và sạch sẽ.
Carey Estes

Mặc dù tốt, điều này không xử lý khoảng trắng. Xem câu trả lời của @ edsioufi để biết cách cải tiến cho giải pháp này.
Badgerspot

Nếu có văn bản ẩn bên trong phần tử, thì nó sẽ làm lệch chiều rộng của bạn. Để giải thích điều này, hãy chắc chắn xóa các nút ẩn trước khi tính chiều rộng văn bản. Để loại bỏ các nút ẩn một cách an toàn, bạn có thể nên tạo một bản sao trước và thực hiện việc xóa ở đó.
thdoan

36

Giải pháp của tôi

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

Về cơ bản là một cải tiến so với Rune, điều đó không .htmlquá nhẹ


Bởi Ajarn Gerhard đã đăng này như một câu trả lời: không này làm việc trong IE8 vì bạn đang bỏ lỡ một /trước khung bế mạc <span>tag:calculator = $('<span style="display: inline-block;" />'),
Petr R.

1
Điều này dường như trả về null nếu có phần tử con bên dưới phần tử bạn đang đo. Nó có thể hoạt động mà không có phần tử con không? Xem jsfiddle.net/h22tj/41
Casper

+1 - Tôi chưa bao giờ biết rằng có một cái mở (), điều đó đã khiến tôi đau buồn vô hạn.
Orwellophile

Nó luôn trả về null trên Chrome.
emeraldhieu

12

Các textWidthhàm được cung cấp trong các câu trả lời và chấp nhận a stringlàm đối số sẽ không tính đến khoảng trắng ở đầu và cuối (chúng không được hiển thị trong vùng chứa giả). Ngoài ra, chúng sẽ không hoạt động nếu văn bản chứa bất kỳ đánh dấu html nào (một chuỗi con <br>sẽ không tạo ra bất kỳ đầu ra nào và&nbsp; sẽ trả về độ dài của một khoảng trắng).

Đây chỉ là vấn đề đối với các textWidthhàm chấp nhận a string, bởi vì nếu một phần tử DOM được cung cấp, và.html() được gọi theo phần tử, thì có lẽ không cần phải sửa lỗi này cho trường hợp sử dụng như vậy.

Nhưng nếu, ví dụ: bạn đang tính toán chiều rộng của văn bản để sửa đổi động chiều rộng của một inputphần tử văn bản khi người dùng nhập (trường hợp sử dụng hiện tại của tôi), bạn có thể sẽ muốn thay thế các khoảng trắng đầu và cuối bằng&nbsp; và mã hóa chuỗi sang html.

Tôi đã sử dụng giải pháp của philfreo vì vậy đây là một phiên bản của nó để sửa lỗi này (với nhận xét về bổ sung):

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

Cảm ơn. Câu trả lời của bạn là có giá trị nhất.
Vishal

1
Thật kỳ lạ, khi tôi thử cái này, nó không sao chép chính xác font-size. Tôi đã phải thêm css('font-size'), this.css('font-size'))vào để nó hoạt động. Bất kỳ ý tưởng tại sao fontmột mình không sao chép giá trị đó?
Gone Coding

@GoneCoding Bạn đã thêm những tính năng bổ sung đó ở đâu?
webmagnets

@webmagnets: Cùng chỗ với .cssphương pháp hiện có , nhưng tôi thấy dấu ngoặc của mình bị sai. Nên css('font-size', this.css('font-size')).
Gone Coding

11

Các hàm chiều rộng của jQuery có thể hơi mờ ám khi cố gắng xác định chiều rộng văn bản do các mô hình hộp không nhất quán. Cách chắc chắn sẽ là chèn div vào bên trong phần tử của bạn để xác định chiều rộng văn bản thực tế:

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

Để sử dụng plugin mini này, chỉ cần:

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

1
Điều này sẽ không cung cấp cho bạn chiều rộng khối hơn là văn bản?
Josh Rickard

-1 Điều này thực sự dường như đo chiều rộng của hộp chứ không phải là chiều rộng văn bản.
Nathan Arthur,

1
Sẽ không chỉ đơn giản là sử dụng một khoảng thay vì một div sẽ khắc phục được vấn đề chiều rộng? Nếu vậy, thì hàm này tốt hơn một chút so với câu trả lời được chấp nhận.
Josh

@Josh: Nếu bạn thay thế nó bằng một, spanbạn chỉ nhận được số không. Đã thử giải pháp này trên một H2, trong đó các phần tử cha bị ẩn tràn và tôi chỉ nhận được độ dài bị cắt ngắn của văn bản. Có lẽ một lời giải thích về cách thức hoạt động của nó sẽ giúp nó hoạt động tốt hơn?
Gone Coding

8

Tôi thấy giải pháp này hoạt động tốt và nó kế thừa phông chữ gốc trước khi định cỡ:

$.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
Tôi đã kết thúc bằng cách sử dụng này, nhưng đã thêm org.css("font-weight"). Ngoài ra, tôi muốn nói rằng if(!text)phần này là không trực quan. Nếu tôi sử dụng, ví dụ: jQuery("#someContainer").textWidth("Lorem ipsum")tôi muốn biết chiều rộng văn bản của "Lorem ipsum" khi được áp dụng trong vùng chứa cụ thể đó.
Đẹp đẽ

8

Cả Rune's và Brain's đều không hoạt động với tôi trong trường hợp phần tử đang giữ văn bản có chiều rộng cố định. Tôi đã làm điều gì đó tương tự như Okamera. Nó sử dụng ít bộ chọn hơn.

CHỈNH SỬA: Nó có thể sẽ không hoạt động đối với các phần tử sử dụng tương đối font-size, vì mã sau chèn htmlCalcphần tử vào bodydo đó làm mất thông tin về quan hệ cha mẹ.

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

Đây là giải pháp tốt nhất cho tôi với sự hỗ trợ của IE8 và sẽ không phá vỡ bất kỳ ràng buộc nào với phần tử trong quá trình này! Cám ơn.
ouija

lưu ý: Trong một phương thức mở rộng jQuery, thisđã là một đối tượng jQuery nên $(this)là dư thừa.
Gone Coding

Điều này đã làm việc sai đối với tôi, trong đó chiều rộng được tính toán quá nhỏ. Câu trả lời được chấp nhận làm việc một cách chính xác
PandaWood

5

Nếu bạn đang cố gắng thực hiện việc này với văn bản trong một hộp được chọn hoặc nếu hai cái đó không hoạt động, hãy thử cái này thay thế:

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

hoặc là

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

nếu bạn muốn lấy văn bản trước


4

vấn đề, bạn đang làm sai, rằng bạn đang gọi một phương thức trên cTxt, đó là một chuỗi đơn giản và không phải là một đối tượng jQuery. cTxt thực sự là văn bản được chứa.


2

Thay đổi nhẹ đối với Nico, vì .children () sẽ trả về một tập hợp trống nếu chúng ta đang tham chiếu đến một phần tử văn bản như h1 hoặc p . Vì vậy, chúng tôi sẽ sử dụng .contents () và sử dụng this thay vì $ (this) vì chúng tôi đang tạo một phương thức trên một đối tượng 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

sau khi đuổi theo một con ma trong hai ngày, cố gắng tìm ra lý do tại sao độ rộng của văn bản không chính xác, tôi nhận ra rằng đó là do các khoảng trắng trong chuỗi văn bản sẽ dừng tính toán độ rộng.

vì vậy, một mẹo khác là kiểm tra xem các khoảng trắng có gây ra sự cố hay không. sử dụng

&nbsp;

không phá vỡ không gian và xem liệu điều đó có khắc phục được không.

các chức năng khác mà mọi người đề xuất cũng hoạt động tốt, nhưng chính khoảng trắng gây ra rắc rối.


Chỉ cần thêm tạm thời white-space: nowrapvào CSS nội tuyến để tránh điều này.
Gone Coding

1

Nếu bạn đang cố gắng xác định chiều rộng của hỗn hợp các nút văn bản và các phần tử bên trong một phần tử nhất định, bạn cần bao bọc tất cả nội dung bằng wrapInner () , tính toán chiều rộng rồi mở gói nội dung.

* Lưu ý: Bạn cũng sẽ cần mở rộng jQuery để thêm một hàm UnrapInner () vì nó không được cung cấp theo mặc định.

$.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 cho .wrapInner. Như bạn có thể biết, xử lý các phần tử văn bản thuần túy trong jQuery là địa ngục. Nếu có bất kỳ phương thức jQuery nào khác có thể áp dụng được, vui lòng cho tôi biết. Tôi đã phải dùng đến .get (0) .children và nó không đẹp.
Orwellophile

1

Mở rộng câu trả lời của @ philfreo:

Tôi đã thêm khả năng kiểm tra text-transform, vì những thứ như text-transform: uppercasethường có xu hướng làm cho văn bản rộng hơn.

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

Gọi getColumnWidth () để lấy văn bản. Điều này hoạt động hoàn toàn tốt.

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

Lưu ý: - Nếu bạn muốn .css nội dòng chỉ chuyển các chi tiết phông chữ theo kiểu.


0

Tôi đã sửa đổi mã của Nico để phù hợp với nhu cầu của tôi.

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

Tôi đang sử dụng .contents () dưới dạng .children () không trả về các nút văn bản mà tôi cần. Tôi cũng nhận thấy rằng chiều rộng trả về bị ảnh hưởng bởi chiều rộng khung nhìn đang gây ra hiện tượng bao gói, vì vậy tôi đang sử dụng white-space: nowrap; để có được chiều rộng chính xác bất kể chiều rộng khung nhìn là bao nhiêu.


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

gần như một lớp lót. Cung cấp cho bạn ký tự đầu tiên


0

Tôi không thể nhận được bất kỳ trong những giải pháp được liệt kê để làm việc 100%, vì vậy đến với điều này lai , dựa trên ý tưởng từ @chmurson (đó là lần lượt dựa trên @Okamera) và cũng từ @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);

Ghi chú:

  • this bên trong phương thức mở rộng jQuery đã là một đối tượng jQuery, vì vậy không cần thêm tất cả $(this) mà nhiều ví dụ có.
  • Nó chỉ thêm phần tử giả vào phần thân một lần và sử dụng lại nó.
  • Bạn cũng nên chỉ định white-space: nowrap, chỉ để đảm bảo rằng nó đo lường nó dưới dạng một dòng duy nhất (và không bao gồm dòng dựa trên kiểu trang khác).
  • Tôi không thể làm cho điều này hoạt động bằng cách sử dụng fontmột mình và cũng phải sao chép rõ ràng font-size. Chưa rõ lý do tại sao (vẫn đang điều tra).
  • Điều này không hỗ trợ các trường đầu vào theo cách @philfreođó.

0

Đôi khi bạn cũng cần đo thêm chiều cao , không chỉ văn bản mà còn cả chiều rộng HTML . Tôi đã trả lời @philfreo và làm cho nó linh hoạt và hữu ích hơn:

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

Độ rộng văn bản có thể khác nhau đối với các bậc cha mẹ khác nhau, ví dụ: nếu bạn thêm văn bản vào thẻ h1, nó sẽ rộng hơn div hoặc nhãn, vì vậy giải pháp của tôi như sau:

<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

Tôi đã gặp sự cố với các giải pháp như @ rune-kaagaard's cho một lượng lớn văn bản. Tôi đã phát hiện ra điều này:

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

tôi nghĩ bạn nên sử dụng $('.calltoaction').val;

Ngoài ra, tôi sẽ sử dụng id (#) thay vì một lớp cho điều đó .. nếu bạn có nhiều hơn một trong các lớp như vậy, nó sẽ xử lý nó như thế nào?


Vâng, có nhiều hơn một trong tài liệu. Tại sao bạn sẽ đề xuất id?
Dom
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.