ปรับความกว้างของฟิลด์อินพุตเป็นอินพุต


171
<html>
  <head>
  </head>
  <body>
    <input type="text" value="1" style="min-width:1px;" />
  </body>
</html>

นี่คือรหัสของฉันและมันไม่ทำงาน มีวิธีอื่นใน HTML, JavaScript, PHP หรือ CSS เพื่อกำหนดความกว้างขั้นต่ำหรือไม่

ฉันต้องการฟิลด์ป้อนข้อความที่มีการเปลี่ยนแปลงความกว้างแบบไดนามิกเพื่อให้ฟิลด์อินพุตของเหลวล้อมรอบเนื้อหา อินพุตทุกตัวมีช่องว่าง2emภายในซึ่งเป็นปัญหาและปัญหาที่สองmin-widthคือว่าไม่ได้ทำงานกับอินพุตเลย

หากฉันตั้งค่าความกว้างมากกว่าที่ต้องการมากกว่าโปรแกรมทั้งหมดยุ่งฉันต้องการความกว้าง 1px มากขึ้นถ้าจำเป็นเท่านั้น


สิ่งนี้ตอบคำถามของคุณหรือไม่ สร้าง textarea พร้อมปรับขนาดอัตโนมัติ
DreamTeK

คำตอบ:


96

ดูเหมือนว่าความคาดหวังของคุณคือสไตล์จะถูกนำไปใช้กับความกว้างของกล่องข้อความตามเนื้อหาของกล่องข้อความ ถ้าเป็นเช่นนั้นคุณจะต้อง js บางอย่างที่จะทำงานในเนื้อหาช่องการเปลี่ยนแปลงบางอย่างเช่นนี้ :

<input id="txt" type="text" onkeypress="this.style.width = ((this.value.length + 1) * 8) + 'px';">

หมายเหตุ: วิธีนี้ใช้ได้เฉพาะเมื่อตัวละครทุกตัว8pxกว้าง


41
@Kerc & Tahbaza: ใช่ แต่จะใช้ได้เฉพาะในกรณีที่ความกว้างของตัวละครทุกตัวมีขนาด 8 พิกเซล
Marcel Korpel

6
ฉันเห็นด้วย Marcel (และรหัสที่โพสต์ไม่ใช่สิ่งที่ฉันเห็นการใช้งานจริง ๆ ) แต่มันแสดงพฤติกรรมที่ต้องการ คุณรู้วิธีคำนวณความกว้างที่แท้จริงของข้อความที่เรนเดอร์โดยคำนึงถึงฟอนต์ขนาดขนาดน้ำหนักการจัดช่องไฟ ฯลฯ หรือไม่? ถ้าเป็นเช่นนั้นโปรดแบ่งปันเพราะฉันจะพบว่ารหัสนั้นมีประโยชน์ในบางโอกาส
Tahbaza

1
- ฉันคิดอยู่แล้วว่ามันเป็นเพียงตัวอย่างเท่านั้น อย่างไรก็ตามการคำนวณความกว้างของอินพุตนั้นไม่ใช่เรื่องยาก ดูคำตอบของฉัน
Marcel Korpel

หน่วย em คือความกว้างของอักขระ "m" สิ่งนี้จะเป็นประโยชน์สำหรับการคำนวณความกว้างของสตริง ฉันเคยเห็นปัญหาข้ามเบราว์เซอร์กับหน่วย em ที่ใช้กับคุณลักษณะบางอย่างดังนั้นลองทดสอบดู
Archonic

7
คุณลืมเหตุการณ์PASTEเพื่อนของฉัน;) คุณควรเปลี่ยนเป็นonInput
vsync

114

ในเวอร์ชันเบราว์เซอร์สมัยใหม่หน่วย CSS chก็มีให้เช่นกัน เพื่อความเข้าใจของฉันมันเป็นหน่วยตัวอักษรที่เป็นอิสระซึ่ง1chเท่ากับความกว้างของตัวละคร0(ศูนย์) ในตัวอักษรที่กำหนดใด ๆ

ดังนั้นสิ่งที่ง่ายเหมือนดังต่อไปนี้สามารถใช้เป็นฟังก์ชั่นปรับขนาด:

var input = document.querySelector('input'); // get the input element
input.addEventListener('input', resizeInput); // bind the "resizeInput" callback on "input" event
resizeInput.call(input); // immediately call the function

function resizeInput() {
  this.style.width = this.value.length + "ch";
}
input{ font-size:1.3em; padding:.5em; }
<input>

ตัวอย่างนั้นจะปรับขนาด "elem" เป็นความยาวของค่าพิเศษ + 2 อักขระ


13
ฉันประหลาดใจที่ความคิดเห็นนี้ไม่ได้รับการโหวตให้สูงขึ้นเพราะมันเป็นโซลูชันที่ยอดเยี่ยมและเบราว์เซอร์ประมาณ 95% ( 1 ) สนับสนุนสิ่งนี้
ฮัสกี้

8
นี้ไม่ได้เป็นคำตอบที่ดีที่ทุกคนตั้งแต่การวัดไม่ถูกต้องและไม่ได้คำนึงถึงรูปแบบบัญชีที่อาจเกิดขึ้นในinputองค์ประกอบเช่นfont-style, letter-spacingและอื่น ๆ ฉันได้แก้ไขคำตอบด้วยการสาธิตสด
vsync

5
ใช้งานได้ดีถ้าคุณใช้แบบอักษรที่มีช่องว่าง ด้วยแบบอักษรอื่นระยะของคุณอาจแตกต่างกันไปตามที่ใช้ความกว้างของอักขระของอักขระ 0 อย่างชัดเจน
Jilles van Gurp

2
มันยอดเยี่ยมจริงๆ แม้ว่าจะทราบว่าบางครั้งมันก็บั๊ก / ไม่ทำงานตามที่ฉันคาดไว้เมื่อ.พบ
Rishav

1
สิ่งนี้จะทำงานได้อย่างสมบูรณ์หากคุณตั้งค่าขนาดกล่องบนอินพุตเป็น 'กล่องเนื้อหา' ด้วยวิธีนี้มันจะไม่สนใจช่องว่างภายในเมื่อคุณตั้งค่าขนาด
Hypersapien

65

ในการคำนวณความกว้างของอินพุตปัจจุบันคุณจะต้องฝังไว้ในspanองค์ประกอบชั่วคราวแนบสิ่งนั้นกับ DOM รับความกว้างที่คำนวณได้ (เป็นพิกเซล) โดยใช้scrollWidthคุณสมบัติและลบออกspanอีกครั้ง แน่นอนว่าคุณจะต้องแน่ใจว่าใช้แบบอักษรตระกูลเดียวกันขนาดตัวอักษร ฯลฯinputในspanองค์ประกอบทั้งสอง ดังนั้นฉันจึงมอบหมายชั้นเรียนเดียวกันให้กับพวกเขา

ฉันแนบฟังก์ชั่นเข้ากับkeyupเหตุการณ์เนื่องจากkeypressตัวอักขระอินพุตยังไม่ได้เพิ่มลงในอินพุตvalueดังนั้นจะส่งผลให้เกิดความกว้างผิด น่าเสียดายที่ฉันไม่ทราบวิธีกำจัดการเลื่อนของฟิลด์ป้อนข้อมูล (เมื่อเพิ่มอักขระไปที่ท้ายฟิลด์) มันเลื่อนเพราะตัวละครจะถูกเพิ่มและแสดงก่อนที่จะadjustWidthOfInput()ถูกเรียก และอย่างที่บอกว่าฉันไม่สามารถทำสิ่งนี้ได้อีกรอบเพราะคุณจะมีค่าของฟิลด์อินพุตก่อนที่จะแทรกตัวอักขระที่กด ฉันจะพยายามแก้ไขปัญหานี้ในภายหลัง

BTW ฉันทดสอบเฉพาะใน Firefox (3.6.8) แต่คุณจะได้รับคะแนนฉันหวังว่า

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Get/set width of &lt;input&gt;</title>
    <style>
      body {
        background: #666;
      }

      .input-element {
        border: 0;
        padding: 2px;
        background: #fff;
        font: 12pt sans-serif;
      }

      .tmp-element {
        visibility: hidden;
        white-space: pre;
      }
    </style>
  </head>
  <body>
    <input id="theInput" type="text" class="input-element" value="1">
    <script>
      var inputEl = document.getElementById("theInput");

      function getWidthOfInput() {
        var tmp = document.createElement("span");
        tmp.className = "input-element tmp-element";
        tmp.innerHTML = inputEl.value.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
        document.body.appendChild(tmp);
        var theWidth = tmp.getBoundingClientRect().width;
        document.body.removeChild(tmp);
        return theWidth;
      }

      function adjustWidthOfInput() {
        inputEl.style.width = getWidthOfInput() + "px";
      }

      adjustWidthOfInput();
      inputEl.onkeyup = adjustWidthOfInput;
    </script>
  </body>
</html>

ผมชอบคำตอบของคุณและยังดำเนินการโดยใช้ jQuery / เน้น: gist.github.com/3745941 อย่างไรก็ตามฉันสามารถตั้งสมมติฐานบางอย่าง: (1) ความกว้างของตัวละครใด ๆ ไม่เกิน 14px, (2) เป็นที่ยอมรับได้ที่จะให้อิลิเมนต์อินพุตขยาย 14px ผ่านค่าขององค์ประกอบ ฉันแนบสิ่งนี้กับเหตุการณ์การเลื่อนลงและมันทำงานได้ดี!
นาธาน

11
คุณควรเพิ่มwhite-space: pre;เป็น css ด้วยวิธีนี้: .tmp-element{ visibility: hidden; white-space: pre;}. มิฉะนั้นช่องว่างสีขาวจะรวมกันและการคำนวณความกว้างล้มเหลว <input>และ<span>พฤติกรรมที่แตกต่างกันเกี่ยวกับการจัดการพื้นที่สีขาว, <input>รักษาพื้นที่สีขาวและ<span>รวมช่องว่างสีขาวตามลำดับเป็นหนึ่งถ้าwhite-space: pre;ไม่ได้เพิ่ม
Timo Kähkönen

2
tmp.getBoundingClientRect().widthจะดีกว่าtmp.scrollWidthเนื่องจากว่าบางครั้งกลับ 0
Lisak

@lisak ขอบคุณฉันปรับคำตอบแล้ว แต่ก็มีคำตอบที่ดีกว่าอยู่แล้วที่นี่
Marcel Korpel

ดีขึ้นหรือไม่ ฉันจะไม่พูดเช่นนั้น คำตอบที่ทำเครื่องหมายว่าไม่มีความแม่นยำผู้อื่น (+ ที่นี่ 1และที่นี่ 2 ) ใช้ jQuery - ฉันทำไม่ได้เพราะทำปฏิกิริยา Canvas ไม่สามารถให้ความสูงข้อความได้ถึง AFAIK แนวคิด: ปัญหาเกี่ยวกับช่องว่างสามารถแก้ไขได้ด้วย:.replace(/ /g, "&nbsp;")
Milan Jaros

30

นี่คือการแก้ไขคำตอบของ Lyth ที่คำนึงถึง:

  • การลบ
  • initialisation
  • ตัวยึด

นอกจากนี้ยังอนุญาตให้มีฟิลด์อินพุตจำนวนเท่าใดก็ได้! หากต้องการดูการทำงาน: http://jsfiddle.net/4Qsa8/

สคริปต์:

$(document).ready(function () {
    var $inputs = $('.resizing-input');

    // Resize based on text if text.length > 0
    // Otherwise resize based on the placeholder
    function resizeForText(text) {
        var $this = $(this);
        if (!text.trim()) {
            text = $this.attr('placeholder').trim();
        }
        var $span = $this.parent().find('span');
        $span.text(text);
        var $inputSize = $span.width();
        $this.css("width", $inputSize);
    }

    $inputs.find('input').keypress(function (e) {
        if (e.which && e.charCode) {
            var c = String.fromCharCode(e.keyCode | e.charCode);
            var $this = $(this);
            resizeForText.call($this, $this.val() + c);
        }
    });

    // Backspace event only fires for keyup
    $inputs.find('input').keyup(function (e) { 
        if (e.keyCode === 8 || e.keyCode === 46) {
            resizeForText.call($(this), $(this).val());
        }
    });

    $inputs.find('input').each(function () {
        var $this = $(this);
        resizeForText.call($this, $this.val())
    });
});

สไตล์:

.resizing-input input, .resizing-input span {
    font-size: 12px;
    font-family: Sans-serif;
    white-space: pre;
    padding: 5px;
}

HTML:

<div class="resizing-input">
    <input type="text" placeholder="placeholder"/>
    <span  style="display:none"></span>
</div>


สวัสดี @Michael รหัสของคุณใช้งานได้ดี แต่ฉันมีปัญหา หนึ่งในฟิลด์ของฉันคือฟิลด์ป้อนข้อมูลอัตโนมัติของ Google และเมื่อฉันเลือกที่อยู่ที่ถูกต้องจากเมนูแบบเลื่อนลงความกว้างของฟิลด์อินพุตจะไม่เปลี่ยนแปลงตามความยาวของที่อยู่ที่เลือก มีวิธีแก้ไขง่ายๆหรือไม่?
Maxence

2
@Maxence การฟังchangeหรือinputกิจกรรมจะเพียงพอ
yarwest

ฉันมีปัญหากับการแสดงของช่วง: ไม่มีการจัดแต่งทรงผมตั้งแต่มันลงทะเบียนช่วงที่มีความกว้าง 0 ดีกว่าที่จะใช้การจัดตำแหน่งแบบสัมบูรณ์พร้อมการมองเห็น: ซ่อนไว้สำหรับช่วง
jayt

สวัสดี @yarwest ขอบคุณสำหรับเคล็ดลับ คุณมีโอกาสใดบ้างที่จะรู้วิธีปรับแต่งสคริปต์ต้นฉบับด้วยการตั้งค่านี้ (ความรู้ของฉันใน Js / jquery มี จำกัด มาก)
Maxence

21

นี่คือทางออก โดยไม่ต้องอักษรพิมพ์ดีดจำเป็นมีเพียงรหัสชิ้นส่วนเล็ก ๆ ของ JavaScript , ไม่จำเป็นต้องคำนวณรูปแบบการคำนวณและแม้สนับสนุน IME , ตำราสนับสนุน RTL

// copy the text from input to the span
    $(function () {
      $('.input').on('input', function () { $('.text').text($('.input').val()); });
    });
    * {
      box-sizing: border-box;
    }
    
    .container {
      display: inline-block;
      position: relative;
    }
    
    .input,
    .text {
      margin: 0;
      padding: 2px 10px;
      font-size: 24px;
      line-height: 32px;
      border: 1px solid #ccc;
      box-radius: 3px;
      height: 36px;
      font: 20px/20px sans-serif;
      /* font: they should use same font; */
    }

    .text {
      padding-right: 20px;
      display: inline-block;
      visibility: hidden;
      white-space: pre;
    }
    
    .input {
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      width: 100%;
    }
    
<script src="https://code.jquery.com/jquery-3.2.0.min.js"></script>

<div class="container">
  <span class="text">
    some text
  </span>
  <input class="input" value="some text" />
</div>

ใช้span.textขนาดเพื่อให้พอดีกับความกว้างของข้อความและให้อินพุตมีขนาดเดียวกันกับposition: absoluteลงในคอนเทนเนอร์ คัดลอกค่าของอินพุตไปยังspanทุกครั้งที่มีการเปลี่ยนแปลง (คุณสามารถเปลี่ยนรหัสชิ้นนี้เป็นวานิลลา js ได้อย่างง่ายดาย) ดังนั้นอินพุตจะ "พอดี" กับขนาดของเนื้อหา


18

เพื่อประสบการณ์ที่ดีขึ้น

คุณควรใช้เหตุการณ์ jQuery keypress () ร่วมกับ String.fromCharCode (e.which) เพื่อรับอักขระที่ถูกกด ดังนั้นคุณสามารถคำนวณสิ่งที่ความกว้างของคุณจะ ทำไม? เพราะมันจะดูเซ็กซี่มากขึ้น :)

นี่คือ jsfiddle ที่ส่งผลให้เกิดพฤติกรรมที่ดีเมื่อเทียบกับวิธีแก้ปัญหาโดยใช้เหตุการณ์ keyup: http://jsfiddle.net/G4FKW/3/

ด้านล่างเป็นวานิลลา JS ซึ่งฟังinputเหตุการณ์ของ<input>องค์ประกอบและตั้งค่าspanพี่น้องให้มีค่าข้อความเดียวกันเพื่อวัด

document.querySelector('input').addEventListener('input', onInput)

function onInput(){
    var spanElm = this.nextElementSibling;
    spanElm.textContent = this.value; // the hidden span takes the value of the input; 
    this.style.width = spanElm.offsetWidth + 'px'; // apply width of the span to the input
};
/* it's important the input and its span have same styling */
input, .measure {
    padding: 5px;
    font-size: 2.3rem;
    font-family: Sans-serif;
    white-space: pre; /* white-spaces will work effectively */
}

.measure{  
  position: absolute;
  left: -9999px;
  top: -9999px;
}
<input type="text" />
<span class='measure'></span>


1
ดูดี แต่ไม่คำนึงถึง Backspace และ Delete
Marcel Korpel

ใช่สำหรับสิ่งนี้คุณต้องมีกิจกรรมการกดปุ่ม คุณสามารถเพิ่มการจัดการเฉพาะสำหรับ backspace และลบโดยทำเช่นนั้น (e.which === 46 สำหรับการลบ e.which === 8 สำหรับ backspace) แต่คุณยังจำเป็นต้องมีกิจกรรมการกดปุ่มเพื่อเข้าถึง e.charCode สำหรับส่วนที่เหลือ
Lyth

หากคุณไม่รองรับ IE8 คุณสามารถใช้เหตุการณ์ oninput แทนการตรวจสอบ e.which: developer.mozilla.org/en-US/docs/Web/Events/input
Frinsh

1
ฉันได้แก้ไขคำตอบของคุณเพื่อกำจัด jQuery และใช้วานิลลา JS เท่านั้น โปรดทราบว่าโซลูชันนี้ยังไม่เหมาะสมเนื่องจากคุณต้องการโซลูชันทั่วไปที่ไม่เกี่ยวข้องกับการเข้ารหัส a spanและ css ด้วยตนเอง
vsync

17

นี่เป็นคำตอบเฉพาะของแองกูลาร์ แต่วิธีนี้ใช้ได้สำหรับฉันและได้รับความพึงพอใจอย่างมากในแง่ของความเรียบง่ายและใช้งานง่าย:

<input [style.width.ch]="value.length" [(ngModel)]="value" />

มันปรับปรุงโดยอัตโนมัติผ่านทางหน่วยตัวอักษรในคำตอบของเจนี่


3
นี้. คือ. มหากาพย์
Daniel Flippance

อย่างจริงจัง. ขลัง
DongBin Kim

13

นี่เป็นวิธีทางเลือกในการแก้ปัญหานี้โดยใช้คุณสมบัติ DIV และคุณสมบัติ 'contenteditable':

HTML:

<div contenteditable = "true" class = "fluidInput" data-placeholder = ""></div>

CSS: (เพื่อให้ DIV มีมิติและทำให้มองเห็นได้ง่ายขึ้น)

.fluidInput {

    display         : inline-block;
    vertical-align  : top;

    min-width       : 1em;
    height          : 1.5em;

    font-family     : Arial, Helvetica, sans-serif;
    font-size       : 0.8em;
    line-height     : 1.5em;

    padding         : 0px 2px 0px 2px;
    border          : 1px solid #aaa;
    cursor          : text;
}


.fluidInput * {

    display         : inline;

}


.fluidInput br  {

    display         : none;

}


.fluidInput:empty:before {

    content         : attr(data-placeholder);
    color           : #ccc;

}

หมายเหตุ: หากคุณวางแผนที่จะใช้สิ่งนี้ภายในองค์ประกอบ FORM ที่คุณวางแผนที่จะส่งคุณจะต้องใช้ Javascript / jQuery เพื่อติดตามเหตุการณ์ส่งเพื่อให้คุณสามารถแยกวิเคราะห์ 'ค่า' ( .innerHTMLหรือ.html()ตามลำดับ) ของ DIV


1
สิ่งนี้สมควรได้รับการโหวตมากขึ้น มันสวยงามและเรียบง่าย (ตราบใดที่การใช้ JS สำหรับการตรวจสอบแบบฟอร์มไม่ใช่ปัญหาสำหรับคุณ)
Daniel Bonnell

3
แต่มันไม่ใช่อินพุต!
Toni Michel Caubet

8

คุณสามารถตั้งค่าความกว้างของอินพุตโดยใช้ขนาดแอ็ตทริบิวต์เช่นกัน ขนาดของอินพุตกำหนดความกว้างของตัวอักษร

อินพุตสามารถปรับขนาดของมันแบบไดนามิกได้โดยฟังเหตุการณ์สำคัญ

ตัวอย่างเช่น

$("input[type='text']").bind('keyup', function () {
    $(this).attr("size", $(this).val().length );
});

JsFiddle ที่นี่


7

คุณสามารถทำอะไรเช่นนี้

// HTML
<input id="input" type="text" style="width:3px" />
// jQuery
$(function(){
  $('#input').keyup(function(){
    $('<span id="width">').append( $(this).val() ).appendTo('body');
    $(this).width( $('#width').width() + 2 );
    $('#width').remove();
  });
});


หากคุณเพิ่มขนาดของการกดคีย์มันจะส่งผลให้เกิดพฤติกรรมที่น่าเกลียด อินพุตต้องเพิ่มขนาดก่อนที่ตัวละครจะเข้ามาเพื่อความสะดวกสบายมากขึ้น
Lyth

5

เพียงเพิ่มคำตอบอื่น ๆ

ฉันสังเกตเห็นว่าทุกวันนี้ในเบราว์เซอร์บางตัวฟิลด์อินพุตมี scrollWidth ซึ่งหมายความว่า:

this.style.width = this.scrollWidth + 'px';

ควรทำงานได้ดี ทดสอบในโครเมี่ยม, Firefox และซาฟารี

สำหรับการสนับสนุนการลบคุณสามารถเพิ่ม '= 0' ก่อนแล้วจึงปรับใหม่

this.style.width = 0; this.style.width = this.scrollWidth + 'px';

3
โปรดเพิ่มรหัสที่เกี่ยวข้องที่นี่เช่นกัน - ลิงค์อาจจะตายในอนาคตและจากนั้นโพสต์นี้ไร้ประโยชน์
Uooo

3
มันใช้งานได้ดีขอบคุณ! ฉันไม่รู้ว่าทำไมคำตอบนี้ไม่มี upvotes เพิ่มเติม มันเป็นโซลูชันที่ง่ายที่สุดและไม่ซับซ้อน (js)
แบบฟอร์ม

4

นี่คือ JS ธรรมดาและปลั๊กอิน jQuery ที่ฉันเขียนซึ่งจะจัดการการปรับขนาดองค์ประกอบอินพุตโดยใช้ Canvas และขนาดตัวอักษร / ตระกูลเพื่อกำหนดความยาวสตริงจริงเมื่อแสดงผล (ใช้ได้เฉพาะใน> IE9, chrome, Safari, firefox, opera และเบราว์เซอร์หลักอื่น ๆ ส่วนใหญ่ที่ใช้องค์ประกอบ Canvas)

PlainJS:

function autoSize(input, o) {
    o || (o = {});
    o.on || (o.on = 'keyup');

    var canvas = document.createElement('canvas');
    canvas.setAttribute('style', 'position: absolute; left: -9999px');
    document.body.appendChild(canvas);

    var ctx = canvas.getContext('2d');

    input.addEventListener(o.on, function () {
        ctx.font = getComputedStyle(this,null).getPropertyValue('font');
        this.style.width = ctx.measureText(this.value + '  ').width + 'px';
    });
}

//Usage
autoSize(document.getElementById('my-input'));

ปลั๊กอิน jQuery:

$.fn.autoSize = function(o) {
  o = $.extend({}, {
    on: 'keyup'
  }, o);

  var $canvas = $('<canvas/>').css({position: 'absolute', left: -9999});
  $('body').append($canvas);

  var ctx = $canvas[0].getContext('2d');

  return this.on(o.on, function(){
    var $this = $(this);
    ctx.font = $this.css('font');
    $this.width(ctx.measureText($this.val()).width + 'px');
  })
}

//Usage:
$('#my-input').autoSize();

หมายเหตุ: สิ่งนี้จะไม่จัดการกับการแปลงข้อความการเว้นวรรคบรรทัดและการเว้นวรรคตัวอักษรและอาจเป็นคุณสมบัติการเปลี่ยนขนาดข้อความอื่น ๆ เพื่อจัดการชุดคุณสมบัติการแปลงข้อความและปรับค่าข้อความให้ตรงกับคุณสมบัตินั้น คนอื่น ๆ อาจจะค่อนข้างตรงไปตรงมา ฉันจะใช้งานถ้าสิ่งนี้เริ่มได้รับแรงฉุด ...


4

เป็นเรื่องที่น่าสังเกตว่าการปรับขนาดที่สวยงามสามารถทำได้เมื่อแบบอักษรมีการ monospaced ดังนั้นเราจึงสามารถปรับขนาดinputองค์ประกอบได้อย่างสมบูรณ์โดยใช้chหน่วย

นอกจากนี้ในวิธีการนี้เราสามารถอัปเดตความกว้างของฟิลด์โดยเพียงแค่อัปเดตตัวแปร CSS ( คุณสมบัติที่กำหนดเอง ) ในinputเหตุการณ์และเราควรดูแลอินพุตที่เติมไว้ล่วงหน้าแล้วในDOMContentLoadedเหตุการณ์

การสาธิต Codepen


มาร์กอัป

<input type="text" value="space mono font" class="selfadapt" />

CSS

:root { --size: 0; }

.selfadapt {
   padding: 5px;
   min-width: 10ch;
   font-family: "space mono";
   font-size: 1.5rem;
   width: calc(var(--size) * 1ch);
}

ในฐานะที่เป็นตัวแปรรูทเราตั้งค่า--size: 0: ตัวแปรนี้จะมีความยาวของอินพุตและมันจะถูกคูณด้วย1chภายในcalc()นิพจน์ โดยค่าเริ่มต้นเราสามารถตั้งค่าความกว้างขั้นต่ำได้เช่น10ch

ส่วน Javascript อ่านความยาวของค่าที่แทรกและอัพเดตตัวแปร--size:

JS

let input = document.querySelector('.selfadapt');
let root  = document.documentElement.style;

/* on input event auto resize the field */
input.addEventListener('input', function() {
   root.setProperty('--size', this.value.length );
});

/* resize the field if it is pre-populated */
document.addEventListener("DOMContentLoaded", function() {
   root.setProperty('--size', input.value.length);
});

ของหลักสูตรนี้ยังคงทำงานแม้ว่าคุณจะไม่ได้ใช้ตัวอักษรพิมพ์ดีด แต่ในกรณีที่คุณจะต้องเปลี่ยนcalc()สูตรโดยคูณ--sizeตัวแปรโดยค่าอื่น (ซึ่งมันเป็นอย่างเคร่งครัดขึ้นอยู่กับfont-familyและfont-size) 1chที่แตกต่างกว่า


3

คำตอบนี้ให้หนึ่งในวิธีที่ถูกต้องที่สุดในการดึงความกว้างของข้อความที่มีอยู่ในเบราว์เซอร์และมีความแม่นยำมากกว่าคำตอบที่ยอมรับ มันใช้องค์ประกอบผ้าใบ html5 และแตกต่างจากคำตอบอื่น ๆ ไม่ได้เพิ่มองค์ประกอบลงใน DOM และจึงหลีกเลี่ยงปัญหา reflow ใด ๆ ที่เกิดจากการเพิ่มองค์ประกอบมากเกินไปใน DOM

อ่านเพิ่มเติมเกี่ยวกับองค์ประกอบ Canvas ที่นี่เกี่ยวกับความกว้างของข้อความ

หมายเหตุ: ตามMDN วิธีการในแบบย่อgetPropertyValue()เช่นฟอนต์อาจไม่น่าเชื่อถือ ฉันขอแนะนำให้รับค่าอย่างแปลกประหลาดเพื่อปรับปรุงความเข้ากันได้ ฉันใช้มันเพื่อความเร็วเท่านั้น

/**
 * returns the width of child text of any DOM node as a float
 */
function getTextWidth(el) {
  // uses a cached canvas if available
  var canvas = getTextWidth.canvas || (getTextWidth.canvas = document.createElement("canvas"));
  var context = canvas.getContext("2d");
  // get the full font style property
  var font = window.getComputedStyle(el, null).getPropertyValue('font');
  var text = el.value;
  // set the font attr for the canvas text
  context.font = font;
  var textMeasurement = context.measureText(text);
  return textMeasurement.width;
}

var input = document.getElementById('myInput');
// listen for any input on the input field
input.addEventListener('input', function(e) {
  var width = Math.floor(getTextWidth(e.target));
  // add 10 px to pad the input.
  var widthInPx = (width + 10) + "px";
  e.target.style.width = widthInPx;
}, false);
#myInput {
  font: normal normal 400 normal 18px / normal Roboto, sans-serif;
  min-width: 40px;
}
<input id="myInput" />


2

คุณสามารถทำได้ง่ายยิ่งขึ้นในเชิงมุมโดยใช้รูปแบบ ngในตัวคำสั่งตัว

ใน html ของคุณ:

  <input ng-style="inputStyle(testdata)" ng-model="testdata" />

ในตัวควบคุมของคุณ:

 $scope.testdata = "whatever";

 $scope.inputStyle = function(str) {
    var charWidth = 7;
    return  {"width": (str.length +1) * charWidth + "px" };
    };

ใน CSS ของคุณ:

input { font-family:monospace; font-size:12px; }

ปรับ charWidth ให้ตรงกับความกว้างของแบบอักษรของคุณ ดูเหมือนว่าจะเป็น 7 ที่ขนาดตัวอักษร 12px;


3
สิ่งนี้ยอดเยี่ยมและสะดวกในการรู้ แต่การเพิ่ม angularjs ให้กับแอพเพื่อปรับขนาดองค์ประกอบการป้อนข้อมูลเป็นสิ่งที่เกินจริงอย่างร้ายแรงโดยเฉพาะอย่างยิ่งเมื่อ OP ถามถึง "HTML, JavaScript, PHP หรือ CSS" ใคร ๆ ก็อาจแย้งว่า jQuery นั้นเกินความจริงสำหรับเรื่องนี้เช่นกัน แต่ไม่เหมือน Angular - การเป็นชุดเครื่องมือ DOM-manipulation เป็นหัวใจสำคัญของวัตถุประสงค์ของ jQuery
vlasits

ฉันควรจะทราบความกว้างของตัวละครที่ถูกพิมพ์ได้อย่างไร? ไม่ใช่เรื่องง่ายที่จะคิดว่ามันเป็นแบบอักษรขนาดเดียว
อีธาน

1
คุณไม่จำเป็นต้องใช้แบบอักษรแบบโมโนโพสต์และไม่จำเป็นต้องใช้แองกูลาร์ คำตอบของเบรนแดนนั้นเหมือนกัน
Dan Dascalescu

2

หากคุณใช้ Bootstrap มันสามารถทำได้ง่ายมาก:

<div contenteditable="true" class="form-control" style="display: inline"></div>

คุณจะต้องดึงเนื้อหาของ div และใส่ไว้ในอินพุตที่ซ่อนไว้ก่อนที่จะส่งแบบฟอร์ม


1

ฉันคิดว่าคุณกำลังตีความคุณสมบัติของmin-width CSSไม่ถูกต้อง ความกว้างขั้นต่ำโดยทั่วไปใช้เพื่อกำหนดความกว้าง DOM ขั้นต่ำในรูปแบบของเหลวเช่น:

input {
  width: 30%;
  min-width: 200px;
}

ที่จะตั้งค่าองค์ประกอบอินพุตให้มีความกว้างต่ำสุด 200 พิกเซล ในบริบทนี้ "px" หมายถึง "pixels"

ตอนนี้หากคุณกำลังพยายามตรวจสอบเพื่อให้แน่ใจว่าช่องใส่มีอย่างน้อยหนึ่งตัวอักษรเมื่อผู้ใช้ส่งมันคุณจะต้องทำการตรวจสอบรูปแบบบางอย่างกับ JavaScript และ PHP หากนั่นคือสิ่งที่คุณพยายามจะทำจริงๆฉันจะแก้ไขคำตอบนี้และทำอย่างดีที่สุดเพื่อช่วยเหลือคุณ


ฉันรู้ว่า px หมายถึงอะไรและฉันรู้ว่าจาวาสคริปต์มีฟังก์ชั่นสำหรับความกว้างขั้นต่ำ แต่มันไม่ทำงานสำหรับข้อความที่ป้อน
Kerc

1
@Kerc:“ จาวาสคริปต์มีฟังก์ชั่นสำหรับความกว้างต่ำสุด” - อันไหน? คุณหมายถึงอะไร -“ มันไม่ทำงาน” ไม่ใช่คำอธิบายที่ดีของปัญหา พยายามอธิบายอย่างละเอียดถึงพฤติกรรมที่ตั้งใจไว้
Marcel Korpel

คุณลองตัวอย่างของฉันมากกว่าที่คุณเห็นว่ามันไม่ใช่ 1 px และคุณก็ไม่ได้ สิ่งนี้จะไม่ทำงานไม่ว่าฉันจะเขียนเป็น html, css
Kerc

อาจจะมีฟังก์ชั่น PHP สำหรับเรื่องนี้ใครรู้หรือไม่?
Kerc

ฉันลองตัวอย่างของคุณแล้ว แต่ฉันคิดว่าฟิลด์อินพุตแบบกว้าง1 พิกเซลไม่ใช่สิ่งที่คุณกำลังมองหา หากเป็นเช่นนั้นลอง<input type="text" value="1" style="width:1px;" />
peterjmag

1

ฉันชอบคำตอบของ Lythจริงๆแต่ก็ต้องการ:

  1. จัดการ backspace และลบ
  2. ไม่ต้องการให้คุณเพิ่มแท็กที่อยู่ติดกันด้วยตนเอง
  3. บังคับใช้ความกว้างขั้นต่ำ
  4. นำไปใช้กับองค์ประกอบที่มีคลาสเฉพาะโดยอัตโนมัติ

ผมดัดแปลง JSFiddle ของเขาและมาพร้อมกับนี้ การปรับปรุงอย่างหนึ่งที่ไม่มีอยู่ในซอนี้จะเป็นการใช้ตัวแยกวิเคราะห์ jQuery CSSเพื่ออ่านความกว้างเริ่มต้นจากกฏ input.textbox-autosize และใช้เป็น minWidth ใช่ฉันแค่ใช้แอททริบิวต์ในตัวซึ่งทำให้เป็นตัวอย่างขนาดกะทัดรัด แต่ไม่เหมาะ เนื่องจากต้องการแอตทริบิวต์เพิ่มเติมในแต่ละอินพุต คุณอาจต้องการวาง minWidth เป็น 100 ในจาวาสคริปต์

HTML:

<div id='applicationHost'>
<div>Name:   <input class='textbox-autosize' data-min-width='100' type="text" /></div>
<div>Email:  <input class='textbox-autosize' data-min-width='100' type="email" /></div>
<div>Points: <input class='textbox-autosize' data-min-width='100' type="number" /></div>
</div>

CSS:

#applicationHost {
    font-family: courier;
    white-space: pre;
}

input.textbox-autosize, span.invisible-autosize-helper {
    padding:0;
    font-size:12px;
    font-family:Sans-serif; 
    white-space:pre;
}
input.textbox-autosize {
    width: 100px; /* Initial width of textboxes */
}

/*
In order for the measurements to work out, your input and the invisible
span need to have the same styling.
*/

JavaScript:

$('#applicationHost').on('keyup', '.textbox-autosize', function(e) {
    // Add an arbitary buffer of 15 pixels.
    var whitespaceBuffer = 15;
    var je = $(this);
    var minWidth = parseInt(je.attr('data-min-width'));
    var newVal = je.val();
    var sizingSpanClass = 'invisible-autosize-helper';
    var $span = je.siblings('span.' + sizingSpanClass).first();
    // If this element hasn't been created yet, we'll create it now.
    if ($span.length === 0) {
        $span = $('<span/>', {
            'class': sizingSpanClass,
            'style': 'display: none;'
        });
        je.parent().append($span);
    }
    $span = je.siblings('span').first();
    $span.text(newVal) ; // the hidden span takes 
    // the value of the input
    $inputSize = $span.width();
    $inputSize += whitespaceBuffer;
    if($inputSize > minWidth)
        je.css("width", $inputSize) ; // apply width of the span to the input
    else
        je.css("width", minWidth) ; // Ensure we're at the min width
});

1

ดีกว่าคือonvalue:

<input id="txt" type="text" onvalue="this.style.width = ((this.value.length + 1) * 8) + 'px';">

นอกจากนี้ยังเกี่ยวข้องกับการวางลากและวาง ฯลฯ


1

นี่คือ 2 เซ็นต์ของฉัน สร้าง div ที่มองไม่เห็นว่างเปล่า เติมเนื้อหาอินพุตและกลับความกว้างกลับไปที่ฟิลด์อินพุต จับคู่ลักษณะข้อความระหว่างแต่ละช่อง

$(".answers_number").keyup(function(){
    $( "#number_box" ).html( $( this ).val() );
    $( this ).animate({
        width: $( "#number_box" ).width()+20
        }, 300, function() {
    });
});
#number_box {
   position: absolute;
   visibility: hidden;
   height: auto;
   width: auto;
   white-space: nowrap;
   padding:0 4px;
   /*Your font styles to match input*/
   font-family:Arial;
   font-size: 30px; 
}
    
.answers_number {
   font-size: 30px; 
   font-family:Arial;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="number" class="answers_number" />
<div id="number_box">
</div>


1

ค่อนข้างง่าย:

oninput='this.style.width = (this.scrollWidth - N) + "px";'

โดยที่ N เป็นตัวเลขบางตัว (2 ในตัวอย่าง 17 ตัวกับสิ่งที่ฉันกำลังพัฒนา) ซึ่งถูกกำหนดโดยการทดลอง

การลบ N จะป้องกันไม่ให้มีพื้นที่เหลือเฟืออันแปลกประหลาดนี้สะสมนานก่อนที่ข้อความจะมาถึงจุดสิ้นสุดของกล่องข้อความ

เปรียบเทียบ. ให้ความสนใจอย่างระมัดระวังว่าขนาดจะเปลี่ยนแปลงไปอย่างไรแม้กระทั่งตัวอักษรตัวแรก

<p>Subtracting N:</p>    
<input type="text" placeholder="enter lots of text here" oninput='this.style.width = (this.scrollWidth-2) + "px";'>

<p>Not Subtracting N:</p>    
<input type="text" placeholder="enter lots of text here" oninput='this.style.width = (this.scrollWidth) + "px";'>


ฉันยังไม่ได้ทดสอบอย่างกว้างขวางกับสิ่งนี้ แต่คุณสามารถเปลี่ยนได้oninput='this.style.width = (this.scrollWidth-2) + "px";'โดยoninput='this.style.width = 0; this.style.width = this.scrollWidth + "px";'กำจัดพื้นที่ที่สะสม
MaxCloutier

0

ฉันแค่ใช้เวลาคิดหาวิธีที่จะทำ
จริง ๆ แล้ววิธีที่ง่ายที่สุดที่ฉันพบคือการย้ายค่าอินพุตเพื่อขยายก่อนอินพุตนั้นโดยรักษาความกว้างของสัญลักษณ์อินพุต 1 แม้ว่าฉันจะไม่สามารถแน่ใจได้ว่ามันเหมาะกับความต้องการเริ่มต้นของคุณ
อาจจะเป็นรหัสพิเศษบางอย่าง แต่ในแอพพลิเคชั่นที่ตอบสนอง + ฟลักซ์มันเป็นวิธีแก้ปัญหาที่ค่อนข้างเป็นธรรมชาติ


0

จากคำตอบของ Michael ฉันได้สร้างเวอร์ชันของตัวเองโดยใช้ jQuery ฉันคิดว่านี่เป็นคำตอบที่ดีที่สุดที่สั้นกว่าและน่าจะทำให้งานเสร็จได้

ฉันกำลังทำสิ่งเดียวกันกับคนส่วนใหญ่ที่นี่โดยใช้ระยะเวลาในการเขียนข้อความอินพุตแล้วเพิ่มความกว้าง จากนั้นฉันจะตั้งค่าความกว้างเมื่อการกระทำkeyupและblurถูกเรียก

นี่คือcodepen ที่ใช้งานได้ codepen นี้แสดงให้เห็นถึงวิธีการนี้สามารถใช้กับหลาย ๆ อินพุตฟิลด์

โครงสร้าง HTML:

<input type="text" class="plain-field" placeholder="Full Name">
<span style="display: none;"></span>

jQuery:

function resizeInputs($text) {
    var text = $text.val().replace(/\s+/g, ' '),
        placeholder = $text.attr('placeholder'),
        span = $text.next('span');
        span.text(placeholder);
    var width = span.width();

    if(text !== '') {
        span.text(text);
    var width = span.width();
    }

    $text.css('width', width + 5);
};

ฟังก์ชั่นด้านบนรับค่าอินพุตตัดขอบช่องว่างพิเศษและตั้งค่าข้อความเป็นส่วนขยายเพื่อให้ได้ความกว้าง หากไม่มีข้อความจะได้รับตัวยึดตำแหน่งแทนและป้อนเข้าไปในช่วงแทน เมื่อมันเข้าสู่ข้อความในช่วงมันก็จะตั้งค่าความกว้างของอินพุต + 5บนความกว้างเป็นเพราะไม่มีการป้อนข้อมูลที่ได้รับการตัดเล็กน้อยในขอบเบราว์เซอร์

$('.plain-field').each(function() {
    var $text = $(this);
    resizeInputs($text);
});

$('.plain-field').on('keyup blur', function() {
    var $text = $(this);
    resizeInputs($text);
});

$('.plain-field').on('blur', function() {
    var $text = $(this).val().replace(/\s+/g, ' ');
    $(this).val($text);
});

หากสามารถปรับปรุงได้โปรดแจ้งให้เราทราบเพราะนี่เป็นวิธีการแก้ปัญหาที่สะอาดที่สุดที่ฉันสามารถทำได้


0

ทำไมไม่ใช้เพียงแค่ CSS

<div id="wrapper">
  <input onkeyup="keyup(event)">
  <div id="ghost"></div>
</div>

function keyup(e) {
	document.getElementById('ghost').innerText = e.target.value;
}
#wrapper {
  position: relative;
  min-width: 30px;
  display: inline-block;
}

input {
  position: absolute;
  left:0;
  right:0;
  border:1px solid blue;
  width: 100%;
}

#ghost {
  color: transparent;
}
<div id="wrapper">
  <input onkeyup="keyup(event)">
  <div id="ghost"></div>
</div>

wrapper {
  position: relative;
  min-width: 30px;
  border: 1px solid red;
  display: inline-block;
}

input {
  position: absolute;
  left:0;
  right:0;
  width: 100%;
}

#ghost {
  color: transparent;
}

@Iain Todd แนะนำให้ใช้รหัสนี้และฉันคิดว่าฉันควรแบ่งปัน


มันไม่ใช่แค่ CSS เป็นเพียงวิธีการ js อื่น ที่น่าสนใจอย่างหนึ่ง
vatavale

0

วิธีกันกระสุนที่ใช้กันทั่วไป:

  1. คำนึงถึงสไตล์ที่เป็นไปได้ทั้งหมดของinputองค์ประกอบที่วัดได้
  2. สามารถใช้การวัดกับอินพุตใดก็ได้โดยไม่ต้องแก้ไขHTMLหรือ

การสาธิต Codepen

var getInputValueWidth = (function(){
  // https://stackoverflow.com/a/49982135/104380
  function copyNodeStyle(sourceNode, targetNode) {
    var computedStyle = window.getComputedStyle(sourceNode);
    Array.from(computedStyle).forEach(key => targetNode.style.setProperty(key, computedStyle.getPropertyValue(key), computedStyle.getPropertyPriority(key)))
  }
  
  function createInputMeassureElm( inputelm ){
    // create a dummy input element for measurements
    var meassureElm = document.createElement('span');
    // copy the read input's styles to the dummy input
    copyNodeStyle(inputelm, meassureElm);
    
    // set hard-coded styles needed for propper meassuring 
    meassureElm.style.width = 'auto';
    meassureElm.style.position = 'absolute';
    meassureElm.style.left = '-9999px';
    meassureElm.style.top = '-9999px';
    meassureElm.style.whiteSpace = 'pre';
    
    meassureElm.textContent = inputelm.value || '';
    
    // add the meassure element to the body
    document.body.appendChild(meassureElm);
    
    return meassureElm;
  }
  
  return function(){
    return createInputMeassureElm(this).offsetWidth;
  }
})();


// delegated event binding
document.body.addEventListener('input', onInputDelegate)

function onInputDelegate(e){
  if( e.target.classList.contains('autoSize') )
    e.target.style.width = getInputValueWidth.call(e.target) + 'px';
}
input{ 
  font-size:1.3em; 
  padding:5px; 
  margin-bottom: 1em;
}

input.type2{
  font-size: 2.5em;
  letter-spacing: 4px;
  font-style: italic;
}
<input class='autoSize' value="type something">
<br>
<input class='autoSize type2' value="here too">


0

คุณสามารถตั้งค่าsizeแอตทริบิวต์ หากคุณใช้เฟรมเวิร์กที่ตอบสนองต่อสิ่งใดสิ่งหนึ่งต่อไปนี้จะเพียงพอ:

<input size="{{ yourValue.length }}" [value]="yourValue" />

แต่ถ้าคุณใช้ pure js คุณควรตั้งตัวจัดการเหตุการณ์เช่น:

<input oninput="this.setAttribute('size', this.value.length)" />
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.