การตรวจจับการเปลี่ยนแปลง Textarea


132

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

ฉันลองใช้เหตุการณ์ onchange แต่ดูเหมือนว่าจะเริ่มต้นเมื่อโฟกัสไม่อยู่เท่านั้น

คำตอบ:


97

คุณจะต้องใช้onkeyup และ onchangeสำหรับสิ่งนี้ onchange จะป้องกันการวางเมนูตามบริบทและการเปิดคีย์อัพจะเริ่มทำงานทุกครั้งที่กดแป้นพิมพ์

ดูคำตอบของฉันเกี่ยวกับวิธีกำหนดความยาวสูงสุดบน textAreaสำหรับตัวอย่างโค้ด


3
แค่อยากจะเน้นย้ำสิ่งที่ Josh พูดไปแล้วว่าคุณควรใช้ keyup ไม่ใช่ keydown สำหรับสิ่งนี้: ดูเหมือนว่า keydown จะถูกเรียกก่อนที่จะมีการเปลี่ยนแปลงใน textarea ดังนั้นคุณจะใช้ความยาวผิด (และคุณไม่ได้ ' ไม่รู้จริงๆว่าคุณเป็นอย่างไร: สามารถพิมพ์หรือลบและอาจมีข้อความที่เลือกไว้หมายความว่ามันมากกว่าแค่ +/- 1)
brianmearns

65
ฉันให้ -1 ขอโทษด้วย! onkeyupเป็นเหตุการณ์ที่น่ากลัวสำหรับการตรวจจับอินพุต ใช้oninputและonpropertychange(สำหรับการรองรับ IE)
Andy E

6
ปัญหา "เท่านั้น" onchangeจะไม่เริ่มทำงานเมื่อมีการตัด / วางเมนูบริบทเกิดขึ้น
ทอม

4
การใช้ onkeydown และ setTimeout ตอบสนองได้ดีกว่ามากเพื่อให้คุณได้รับการตรวจจับการเปลี่ยนแปลงทันทีแทนที่จะรอให้ปล่อยคีย์ หากคุณจำเป็นต้องจับตัดและวางให้ใช้เหตุการณ์ตัดและวาง
Kevin B

1
คำเตือน: onkeyup อาจทำให้คุณมีปัญหา ตัวอย่าง: สมมติว่าคุณควรทำบางอย่างเฉพาะเมื่อเนื้อหาที่ป้อนมีการเปลี่ยนแปลง หากคุณคิดว่าคีย์อัพจะเปลี่ยนอินพุตไม่เป็นความจริง โฟกัสที่อินพุต ใช้ "แท็บ" เพื่อย้ายไปยังฟิลด์ถัดไป ตอนนี้ใช้ "shift + tab" เพื่อกลับไปที่อินพุต คีย์อัพเริ่มทำงาน แต่อินพุตไม่ได้ถูกเปลี่ยนแปลงโดยผู้ใช้
Zig Mandel

117

เป็นปี 2012 ยุคหลังพีซีมาถึงแล้วและเรายังคงต้องต่อสู้กับบางสิ่งที่เป็นพื้นฐานเช่นนี้ นี้ควรจะเป็นเรื่องง่ายมาก

จนกว่าจะถึงเวลาที่ความฝันจะสำเร็จนี่คือวิธีที่ดีที่สุดในการทำเช่นนี้ข้ามเบราว์เซอร์: ใช้การผสมผสานระหว่างเหตุการณ์inputและonpropertychangeเหตุการณ์เช่นนี้

var area = container.querySelector('textarea');
if (area.addEventListener) {
  area.addEventListener('input', function() {
    // event handling code for sane browsers
  }, false);
} else if (area.attachEvent) {
  area.attachEvent('onpropertychange', function() {
    // IE-specific event handling code
  });
}

inputเหตุการณ์ดูแลIE9 + FF, Chrome, Opera และ SafariและonpropertychangeดูแลIE8 (มันยังทำงานร่วมกับ IE6 และ 7 แต่มีข้อบกพร่องบางอย่าง)

ประโยชน์ของการใช้inputและการonpropertychangeที่พวกเขาไม่ได้ยิงไม่จำเป็น (เช่นเมื่อกดCtrlหรือShiftคีย์); ดังนั้นหากคุณต้องการที่จะเรียกใช้การดำเนินการค่อนข้างแพงเมื่อเนื้อหา textarea เปลี่ยนแปลงนี้เป็นวิธีที่จะไป

ตอนนี้ IE เช่นเคยไม่ได้งานครึ่ง assed ของการสนับสนุนนี้: ค่าinputมิได้onpropertychangeเกิดเพลิงไหม้ใน IE เมื่อตัวละครจะถูกลบออกจากพื้นที่ข้อความ ดังนั้นหากคุณจำเป็นต้องจัดการกับการลบอักขระใน IE ให้ใช้keypress(ซึ่งตรงข้ามกับการใช้keyup/ keydownเนื่องจากจะเริ่มทำงานเพียงครั้งเดียวแม้ว่าผู้ใช้จะกดปุ่มค้างไว้ก็ตาม)

ที่มา: http://www.alistapart.com/articles/expanding-text-areas-made-elegant/

แก้ไข:ดูเหมือนว่าโซลูชันข้างต้นจะไม่สมบูรณ์แบบตามที่ระบุไว้อย่างถูกต้องในความคิดเห็น: การมีอยู่ของaddEventListenerคุณสมบัติบน textarea ไม่ได้หมายความว่าคุณกำลังทำงานกับเบราว์เซอร์ที่มีสติ ในทำนองเดียวกันการมีอยู่ของattachEventคุณสมบัติไม่ได้หมายความถึง IE หากคุณต้องการให้รหัสของคุณแน่นมากคุณควรพิจารณาเปลี่ยนรหัสนั้น ดูความคิดเห็นของ Tim Downสำหรับคำแนะนำ


1
นี่คือแนวทางที่ดีที่สุด ฉันไม่ชอบการอนุมานที่นี่ (การสนับสนุนเบราว์เซอร์addEventListenerไม่ได้หมายความว่าสนับสนุนinputเหตุการณ์หรือในทางกลับกัน) การตรวจจับคุณลักษณะจะดีกว่า ดูโพสต์บล็อกนี้สำหรับการสนทนาเกี่ยวกับเรื่องนี้
Tim Down

เห็นด้วยกับทิมในเรื่องนี้ oninputเป็นวิธีที่เราควรทำ แต่คุณอาจไม่ควรใช้addEventListenerเป็นการทดสอบการรองรับเบราว์เซอร์ +1 ไม่ว่าในกรณีใด ๆ
Ben D

1
ไม่เห็นด้วยอินพุตจะไม่ดูแล IE9 ตัด / วางผ่านเมนูบริบทน่าเสียดายที่มีการป้อนข้อมูลด้วยเช่นกันและ backspace ก็เช่นกัน ฉันไม่ได้กังวลที่จะทดสอบ แต่ฉันจะไม่วางเงินเดิมพันที่ IE10 + แก้ไขปัญหานั้น
Stefan Steiger

1
@StefanSteiger ซึ่งเป็นสาเหตุที่คำตอบของฉันแนะนำให้ใช้keypressเหตุการณ์เพื่อจัดการกรณีนั้นใน IE9 (และอาจเป็นรุ่นที่ใหม่กว่าด้วย)
Vicky Chijwani

inputตัวจัดการเหตุการณ์ยังสามารถกำหนดได้โดยการใช้.oninputคุณสมบัติอ็อบเจ็กต์
จับ

20
  • สำหรับ Google-Chrome oninput จะเพียงพอ (ทดสอบบน Windows 7 ด้วยเวอร์ชัน 22.0.1229.94 ม.)
  • สำหรับ IE 9 oninput จะจับทุกอย่างยกเว้นตัดผ่านเมนูบริบทและ backspace
  • สำหรับ IE 8 จำเป็นต้องใช้ onpropertychange เพื่อจับการวางนอกเหนือจาก oninput
  • สำหรับ IE 9 + 8 จำเป็นต้องใช้ onkeyup เพื่อจับ backspace
  • สำหรับ IE 9 + 8 onmousemove เป็นวิธีเดียวที่ฉันพบในการจับการตัดผ่านเมนูบริบท

ไม่ได้ทดสอบบน Firefox

    var isIE = /*@cc_on!@*/false; // Note: This line breaks closure compiler...

    function SuperDuperFunction() {
        // DoSomething
    }


    function SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally() {
        if(isIE) // For Chrome, oninput works as expected
            SuperDuperFunction();
    }

<textarea id="taSource"
          class="taSplitted"
          rows="4"
          cols="50"
          oninput="SuperDuperFunction();"
          onpropertychange="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onmousemove="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();"
          onkeyup="SuperDuperFunctionBecauseMicrosoftMakesIEsuckIntentionally();">
Test
</textarea>

1
ชื่อฟังก์ชันที่ยอดเยี่ยม :)
Jonas Gröger

8

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

var text = document.createElement('textarea');
text.rows = 10;
text.cols = 40;
document.body.appendChild(text);

text.onkeyup = function(){
var callcount = 0;
    var action = function(){
        alert('changed');
    }
    var delayAction = function(action, time){
        var expectcallcount = callcount;
        var delay = function(){
            if(callcount == expectcallcount){
                action();
            }
        }
        setTimeout(delay, time);
    }
    return function(eventtrigger){
        ++callcount;
        delayAction(action, 1200);
    }
}();

วิธีนี้ทำงานโดยการทดสอบว่าเหตุการณ์ล่าสุดเกิดขึ้นภายในช่วงเวลาที่ล่าช้าหรือไม่ โชคดี!


1
+1 สำหรับ 'การควบคุมปริมาณ' การดำเนินการที่ล่าช้า! ฉันใช้สิ่งที่คล้ายกันในแอปของฉัน
psulek

7

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

    $('div.lawyerList').on('change','textarea',function(){
      // Change occurred so count chars...
    });

หรือ

    $('textarea').on('change',function(){
      // Change occurred so count chars...
    });

4
ฉันพบว่าเหตุการณ์การเปลี่ยนแปลงไม่สอดคล้องกับ jQuery มากกว่า JS ธรรมดา ฉันใช้ jQuery bind("input cut paste"...และมันใช้งานได้ดี - พิมพ์ตัดและวางโดยใช้แป้นพิมพ์หรือเมนูบริบท แม้แต่ลาก / วางข้อความ
Lawrence Dol

2
น่าเสียดายที่ FF ไม่ได้ยิงchangeเหตุการณ์สำหรับtextarea.
dma_k

4

คุณสามารถฟังเหตุการณ์เกี่ยวกับการเปลี่ยนแปลงพื้นที่ข้อความและทำการเปลี่ยนแปลงตามที่คุณต้องการ นี่คือตัวอย่างหนึ่ง

(() => {
	const textArea = document.getElementById('my_text_area');
  textArea.addEventListener('input', () => {
    let textLn =  textArea.value.length;
    if(textLn >= 100) {
      textArea.style.fontSize = '10pt';
    }

  })
})()
<html>
<textarea id='my_text_area' rows="4" cols="50" style="font-size:40pt">
This text will change font after 100.
</textarea>
</html>


1

คีย์อัพควรเพียงพอหากจับคู่กับแอตทริบิวต์การตรวจสอบความถูกต้อง / รูปแบบอินพุต HTML5 ดังนั้นสร้างรูปแบบ (regex) เพื่อตรวจสอบความถูกต้องของอินพุตและดำเนินการกับสถานะ. checkValidity () สิ่งที่ต้องการด้านล่างสามารถใช้งานได้ ในกรณีของคุณคุณต้องการให้นิพจน์ทั่วไปตรงกับความยาว วิธีการแก้ปัญหาของฉันคือในการใช้งาน / การสาธิตสามารถออนไลน์ที่นี่

<input type="text" pattern="[a-zA-Z]+" id="my-input">

var myInput = document.getElementById = "my-input";

myInput.addEventListener("keyup", function(){
  if(!this.checkValidity() || !this.value){
    submitButton.disabled = true;
  } else {
    submitButton.disabled = false;
  }
});

0

รหัสที่ฉันใช้สำหรับ IE 11 โดยไม่มี jquery และสำหรับ textarea เดียว:

javascript:

// Impede que o comentário tenha mais de num_max caracteres
var internalChange= 0; // important, prevent reenter
function limit_char(max)
{ 
    if (internalChange == 1)
    {
        internalChange= 0;
        return;
    }
    internalChange= 1;
    // <form> and <textarea> are the ID's of your form and textarea objects
    <form>.<textarea>.value= <form>.<textarea>.value.substring(0,max);
}

และ html:

<TEXTAREA onpropertychange='limit_char(5)' ...

-1

ลองอันนี้. มันง่ายมากและตั้งแต่ปี 2016 ฉันมั่นใจว่ามันจะใช้ได้กับเบราว์เซอร์ส่วนใหญ่

<textarea id="text" cols="50" rows="5" onkeyup="check()" maxlength="15"></textarea> 
<div><span id="spn"></span> characters left</div>

function check(){
    var string = document.getElementById("url").value
    var left = 15 - string.length;
    document.getElementById("spn").innerHTML = left;
}

ดังนั้นคุณจะได้รับ url โดย id แต่ไม่ปรากฏในรหัสของคุณ
AbsoluteƵERØ

-8

สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือการตั้งค่าฟังก์ชันที่จะเรียกตามระยะเวลาที่กำหนดและฟังก์ชันนี้เพื่อตรวจสอบเนื้อหาของพื้นที่ข้อความของคุณ

self.setInterval('checkTextAreaValue()', 50);

7
การสำรวจความคิดเห็นเป็นความคิดที่แย่มาก มันจะทำลายประสิทธิภาพ นอกจากนี้เช่นเดียวกับโพสต์อื่น ๆ มีวิธีแก้ปัญหาบางอย่าง
Pier-Olivier Thibault

2
นี่คือศตวรรษที่ 21 เบราว์เซอร์ไม่ควรมีปัญหาในการจัดการการเปรียบเทียบสตริงทุกๆ 50 มิลลิวินาที แคชตัวเลือกของคุณและนี่เป็นโซลูชันที่ยอมรับได้อย่างสมบูรณ์
nullability
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.