การคำนวณความกว้างของข้อความ


101

ฉันพยายามคำนวณความกว้างของข้อความโดยใช้ jQuery ฉันไม่แน่ใจว่าอะไร แต่ฉันทำอะไรผิดแน่ ๆ

ดังนั้นนี่คือรหัส:

var c = $('.calltoaction');

var cTxt = c.text();

var cWidth =  cTxt.outerWidth();

c.css('width' , cWidth);

แล้วรหัสนั้นใช้งานไม่ได้ในทางใด? มันต้องทำอะไรแตกต่างกัน?
Sixten Otto

คำตอบ:


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
เบ็น

เนียน. +1. ดูเหมือนว่าคุณจะไม่มีเครื่องหมายเซมิโคลอนในบรรทัดที่สามหลังจาก'</span>'นั้นแม้ว่าจะดูเหมือนจะไม่สร้างความแตกต่าง (ใช้งานได้หรือไม่มีบน FF9)
ฉาย

21
โปรดใช้ความระมัดระวังด้วย ... วิธีนี้จะยกเลิกการเชื่อมโยงเหตุการณ์ใด ๆ ในองค์ประกอบย่อย
brianreavis

ฉันได้ลองใช้ฟังก์ชันนี้หลายวิธีแล้ว แต่มันกลับเป็นโมฆะ มีใครช่วยโพสต์ไวยากรณ์สำหรับการใช้งานฟังก์ชันนี้ได้ไหม ฉันเรียกใช้ฟังก์ชัน. textWidth () บนวัตถุ jQuery หรือไม่ ฉันส่งข้อความไปยังฟังก์ชันนี้หรือไม่ ฉันเรียกใช้ฟังก์ชันนี้เป็นฟังก์ชัน jQuery (เช่น $ .textWidth (jqObject) หรือไม่เพราะดูเหมือนจะไม่มีตัวเลือกใดที่ใช้งานได้ขอบคุณ ...
moosefetcher

2
@moosefetcher คุณจะทำ $ (ตัวเลือก) .textWidth (); ดูที่นี่learn.jquery.com/plugins/basic-plugin-creation/…
uesports135

89

นี่คือฟังก์ชั่นที่ดีกว่าที่โพสต์ไว้เพราะ

  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 Rostovtsev

Fantastico! เรียบง่ายและสะอาด
Carey Estes

ในขณะที่ดีสิ่งนี้ไม่ได้จัดการช่องว่าง ดูคำตอบของ @edsioufi สำหรับการปรับปรุงโซลูชันนี้
Badgerspot

หากมีข้อความที่ซ่อนอยู่ภายในองค์ประกอบนั้นจะทำให้ความกว้างของคุณเอียง ในการพิจารณาสิ่งนี้อย่าลืมลบโหนดที่ซ่อนอยู่ก่อนคำนวณความกว้างของข้อความ หากต้องการลบโหนดที่ซ่อนอยู่อย่างปลอดภัยคุณควรทำการโคลนก่อนและทำการลบที่นั่น
ถึง

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เบา ๆ


โดยอาจารย์ Gerhardที่โพสต์เป็นคำตอบ:สิ่งนี้ใช้ไม่ได้ใน IE8 เนื่องจากคุณไม่มีเครื่องหมาย/ก่อนวงเล็บปิดของ<span>แท็ก:calculator = $('<span style="display: inline-block;" />'),
Petr R.

1
ดูเหมือนว่าจะส่งคืนค่าว่างหากมีองค์ประกอบลูกอยู่ด้านล่างองค์ประกอบที่คุณกำลังวัด สามารถทำให้ใช้งานได้โดยไม่มีองค์ประกอบย่อยหรือไม่? ดูjsfiddle.net/h22tj/41
Casper

+1 - ฉันไม่เคยรู้มาก่อนว่ามีการแกะ () ซึ่งทำให้ฉันเสียใจไม่รู้จบ
Orwellophile

มันจะคืนค่า null บน Chrome เสมอ
emeraldhieu

12

textWidthฟังก์ชั่นที่ระบุไว้ในคำตอบและที่ยอมรับstringเป็นอาร์กิวเมนต์จะไม่บัญชีสำหรับชั้นนำและช่องว่างต่อท้ายสีขาว (เหล่านี้จะไม่แสดงผลในภาชนะหุ่น) นอกจากนี้จะไม่ทำงานหากข้อความมีมาร์กอัป html (สตริงย่อย<br>จะไม่สร้างเอาต์พุตใด ๆ และ&nbsp;จะคืนค่าความยาวของช่องว่างเดียว)

นี่เป็นเพียงปัญหาสำหรับtextWidthฟังก์ชันที่ยอมรับ a stringเนื่องจากหากมีการกำหนดองค์ประกอบ DOM และ.html()ถูกเรียกใช้ตามองค์ประกอบนั้นอาจไม่จำเป็นต้องแก้ไขปัญหานี้สำหรับกรณีการใช้งานดังกล่าว

แต่ตัวอย่างเช่นหากคุณกำลังคำนวณความกว้างของข้อความเพื่อปรับเปลี่ยนความกว้างของinputองค์ประกอบข้อความแบบไดนามิกตามประเภทผู้ใช้ (กรณีการใช้งานปัจจุบันของฉัน) คุณอาจต้องการแทนที่ช่องว่างนำหน้าและต่อท้ายด้วย&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คนเดียวไม่คัดลอกค่านั้น?
Gone Coding

@GoneCoding คุณเพิ่มความพิเศษเหล่านั้นตรงไหน?
webmagnets

@webmagnets: ที่เดียวกับ.cssวิธีที่มีอยู่แต่ฉันเห็นว่าวงเล็บของฉันไม่ถูกต้อง css('font-size', this.css('font-size'))ควรจะเป็น
Gone Coding

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

-1 สิ่งนี้ดูเหมือนจะวัดความกว้างของกล่องแทนที่จะเป็นความกว้างของข้อความ
Nathan Arthur

1
จะไม่ใช้สแปนแทน div เพื่อแก้ไขปัญหาความกว้างใช่หรือไม่? ถ้าเป็นเช่นนั้นฟังก์ชันนี้จะดีกว่าคำตอบที่ยอมรับเล็กน้อย
Josh

@ Josh: ถ้าคุณแทนที่ด้วยspanคุณจะได้ศูนย์ ลองวิธีแก้ปัญหานี้กับH2องค์ประกอบหลักที่ซ่อนอยู่มากเกินไปและฉันได้รับความยาวของข้อความที่ถูกตัดทอนเท่านั้น บางทีคำอธิบายว่าสิ่งนี้ควรจะทำงานได้อย่างไรจะช่วยให้ทำงานได้ดีขึ้น?
Gone Coding

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 และจะไม่ทำลายการเชื่อมโยงใด ๆ กับองค์ประกอบในกระบวนการ! ขอบคุณ.
ผีถ้วยแก้ว

หมายเหตุ: ในวิธีการขยายthisjQuery เป็นวัตถุ jQuery อยู่แล้วจึง$(this)ซ้ำซ้อน
Gone Coding

สิ่งนี้ทำงานผิดสำหรับฉันเนื่องจากความกว้างที่คำนวณได้นั้นเล็กเกินไป คำตอบที่ยอมรับทำงานได้อย่างถูกต้อง
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

การเปลี่ยนแปลงเล็กน้อยของนิโก้ตั้งแต่ .children () จะกลับเซตว่างถ้าเรากำลังอ้างอิงองค์ประกอบข้อความเช่นh1หรือพี ดังนั้นเราจะใช้ .contents () แทนและใช้สิ่งนี้แทน $ (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;
    };

1

หลังจากไล่ผีมาสองวันพยายามหาสาเหตุที่ความกว้างของข้อความไม่ถูกต้องฉันรู้ว่าเป็นเพราะช่องว่างสีขาวในสตริงข้อความที่จะหยุดการคำนวณความกว้าง

ดังนั้นเคล็ดลับอีกประการหนึ่งคือการตรวจสอบว่าช่องว่างทำให้เกิดปัญหาหรือไม่ ใช้

&nbsp;

พื้นที่ที่ไม่ทำลายและดูว่าสามารถแก้ไขได้หรือไม่

ฟังก์ชั่นอื่น ๆ ที่ผู้คนแนะนำก็ใช้ได้ดีเช่นกัน แต่เป็นช่องว่างที่ทำให้เกิดปัญหา


เพิ่มลงwhite-space: nowrapใน CSS แบบอินไลน์ชั่วคราวเพื่อหลีกเลี่ยงปัญหานี้
Gone Coding

1

หากคุณกำลังพยายามกำหนดความกว้างของการผสมของโหนดข้อความและองค์ประกอบภายในองค์ประกอบที่กำหนดคุณต้องรวมเนื้อหาทั้งหมดด้วยwrapInner ()คำนวณความกว้างแล้วแกะเนื้อหาออก

* หมายเหตุ: คุณจะต้องขยาย jQuery เพื่อเพิ่มฟังก์ชัน uncrapInner () เนื่องจากไม่ได้ระบุไว้โดยค่าเริ่มต้น

$.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 สำหรับ. wrapInner อย่างที่คุณทราบการจัดการกับองค์ประกอบข้อความบริสุทธิ์ใน jQuery นั้นเป็นนรก หากมีวิธีการ jQuery อื่น ๆ ที่ใช้ได้โปรดแจ้งให้เราทราบ ฉันต้องหันไปหา. get (0) เด็ก ๆ แล้วมันไม่สวยเลย
Orwellophile

1

ขยายคำตอบของ @ philfreo:

ฉันได้เพิ่มความสามารถในการตรวจสอบtext-transformเนื่องจากสิ่งต่างๆtext-transform: uppercaseมักจะทำให้ข้อความกว้างขึ้น

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

เรียก getColumnWidth () เพื่อรับข้อความ ทำงานได้ดีอย่างสมบูรณ์

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

หมายเหตุ: - หากคุณต้องการให้. css แบบอินไลน์ส่งรายละเอียดแบบอักษรในรูปแบบเท่านั้น


0

ฉันแก้ไขรหัสของ Nico เพื่อให้เหมาะกับความต้องการของฉัน

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

ฉันใช้ . contents ()เป็น .children () ไม่ส่งคืนโหนดข้อความที่ฉันต้องการ ฉันยังพบว่าความกว้างที่ส่งคืนได้รับผลกระทบจากความกว้างของวิวพอร์ตซึ่งทำให้เกิดการห่อดังนั้นฉันจึงใช้ช่องว่าง: nowrap; เพื่อให้ได้ความกว้างที่ถูกต้องโดยไม่คำนึงถึงความกว้างของวิวพอร์ต


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

เกือบหนึ่งซับ ให้คุณมีอักขระตัวแรก


0

ฉันไม่สามารถหาวิธีแก้ปัญหาใด ๆ ที่ระบุว่าใช้งานได้ 100% ดังนั้นจึงเกิดไฮบริดนี้ขึ้นโดยอาศัยแนวคิดจาก @chmurson (ซึ่งอิงตาม @Okamera) และจาก @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);

หมายเหตุ:

  • thisภายในวิธีการขยาย jQuery นั้นเป็นวัตถุ jQuery อยู่แล้วดังนั้นจึงไม่จำเป็นต้องมีสิ่งพิเศษทั้งหมด$(this)ที่มีในตัวอย่างมากมาย
  • เพียงเพิ่มองค์ประกอบจำลองให้กับร่างกายเพียงครั้งเดียวและนำกลับมาใช้ใหม่
  • นอกจากนี้คุณควรระบุwhite-space: nowrapเพียงเพื่อให้แน่ใจว่ามีการวัดเป็นบรรทัดเดียว (และไม่ใช่การตัดบรรทัดตามสไตล์หน้าอื่น ๆ )
  • ฉันไม่สามารถใช้งานได้โดยใช้fontคนเดียวและต้องคัดลอกอย่างชัดเจนfont-sizeด้วย ไม่แน่ใจว่าทำไม (ยังคงตรวจสอบอยู่)
  • สิ่งนี้ไม่สนับสนุนช่องป้อนข้อมูลด้วยวิธี@philfreoนี้

0

บางครั้งคุณต้องวัดความสูงเพิ่มเติมไม่ใช่เฉพาะข้อความแต่ต้องวัดความกว้าง HTMLด้วย ฉันตอบ @philfreo และทำให้มันยืดหยุ่นและมีประโยชน์มากขึ้น:

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

ความกว้างของข้อความอาจแตกต่างกันสำหรับผู้ปกครองที่แตกต่างกันเช่นถ้าคุณเพิ่มข้อความลงในแท็ก h1 มันจะกว้างกว่า div หรือ label ดังนั้นวิธีการแก้ปัญหาของฉันจึงเป็นดังนี้:

<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

ฉันมีปัญหากับวิธีแก้ปัญหาเช่น @ rune-kaagaard สำหรับข้อความจำนวนมาก ฉันค้นพบสิ่งนี้:

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

ฉันคิดว่าคุณควรใช้ $('.calltoaction').val;

นอกจากนี้ฉันจะใช้ id (#) แทนคลาสสำหรับสิ่งนั้น .. ถ้าคุณมีมากกว่าหนึ่งคลาสที่จะจัดการกับมัน?


ใช่มีมากกว่าหนึ่งในเอกสาร ทำไมคุณถึงแนะนำ id?
Dom
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.