Phát hiện tất cả các thay đổi đối với <kiểu nhập = văn bản trên mạng> (ngay lập tức) bằng JQuery


397

Có nhiều cách giá trị của một <input type="text">có thể thay đổi, bao gồm:

  • nhấn phím
  • sao chép dán
  • sửa đổi bằng JavaScript
  • tự động hoàn thành bởi trình duyệt hoặc thanh công cụ

Tôi muốn hàm JavaScript của mình được gọi (với giá trị đầu vào hiện tại) bất cứ khi nào nó thay đổi. Và tôi muốn nó được gọi ngay lập tức, không chỉ khi đầu vào mất tập trung.

Tôi đang tìm cách sạch nhất và mạnh mẽ nhất để làm điều này trên tất cả các trình duyệt (tốt nhất là sử dụng jQuery).



Câu trả lời:


352

Mã jQuery này nắm bắt các thay đổi ngay lập tức đối với bất kỳ phần tử nào và sẽ hoạt động trên tất cả các trình duyệt:

 $('.myElements').each(function() {
   var elem = $(this);

   // Save current value of element
   elem.data('oldVal', elem.val());

   // Look for changes in the value
   elem.bind("propertychange change click keyup input paste", function(event){
      // If value has changed...
      if (elem.data('oldVal') != elem.val()) {
       // Updated stored value
       elem.data('oldVal', elem.val());

       // Do action
       ....
     }
   });
 });

19
Đối với tham chiếu của mọi người, inputlà sự kiện HTML5 mà tôi tin rằng sẽ bao gồm tất cả các trình duyệt hiện đại ( tham chiếu MDN ). keyupnên bắt phần còn lại, mặc dù có một chút chậm trễ ( inputđược kích hoạt khi nhấn phím xuống). propertychangelà một sự kiện MS độc quyền và tôi không chắc pastecó thực sự cần thiết hay không.
Jo Liss

71
Tôi sai hay điều này không xử lý khi văn bản thay đổi qua javascript như document.getElementById('txtInput').value = 'some text';
Mehmet Ataş

5
Mehmet, mã không có nghĩa là bắt các giá trị được thay đổi thông qua JS.
phatmann

12
@ MehmetAtaş là một phần chính xác. Tham chiếu cho inputsự kiện ở đây nói rằng nó không kích hoạt khi nội dung được sửa đổi thông qua JavaScript. Tuy nhiên, onpropertychangesự kiện này không kích hoạt sửa đổi thông qua JS (xem tại đây ). Vì vậy, mã này sẽ hoạt động khi nội dung được sửa đổi thông qua JS trên IE, nhưng sẽ không hoạt động trên các trình duyệt khác.
Vicky Chijwani

2
Bạn có thể kích hoạt một sự kiện tùy chỉnh trên đầu vào khi trao đổi thuộc tính, keyup, v.v. và sau đó sử dụng nó ở bất cứ đâu.
Ivan Ivković

122

Một giải pháp ưa thích thời gian thực cho jQuery> = 1.9

$("#input-id").on("change keyup paste", function(){
    dosomething();
})

nếu bạn cũng muốn phát hiện sự kiện "nhấp chuột", chỉ cần:

$("#input-id").on("change keyup paste click", function(){
    dosomething();
})

nếu bạn đang sử dụng jQuery <= 1.4, chỉ cần sử dụng livethay vì on.


3
Điều này có một nhược điểm. Nếu bạn rời khỏi trường nhập bằng phím tab - nó sẽ ném sự kiện keyup ngay cả khi nội dung không được chỉnh sửa.
Pawka

2
Làm cách nào để phát hiện khi datetimepicker điền # input-id? Không có sự kiện (thay đổi, dán) nào hoạt động.
Pathros

Điều đó thật tuyệt! Tôi đã thử nó với jquery 1.8.3 và nó hoạt động. Tôi vẫn còn một số mã livequery () mà tôi phải thay thế vì vậy tôi không thể nâng cấp lên 1.9.1. Tôi biết nó đã cũ nhưng toàn bộ trang web cũng vậy.
Asle

FYI: Những sự kiện này sẽ kích hoạt với giá trị trống nếu bàn phím được sử dụng để chọn ngày không hợp lệ. I E. Ngày 30 tháng 2. stackoverflow.com/questions/48564568/
Mạnh

107

Thật không may, tôi nghĩ rằng setIntervalchiến thắng giải thưởng:

<input type=text id=input_id />
<script>
setInterval(function() { ObserveInputValue($('#input_id').val()); }, 100);
</script>

Đây là giải pháp sạch nhất, chỉ có 1 dòng mã. Nó cũng mạnh mẽ nhất, vì bạn không phải lo lắng về tất cả các sự kiện / cách khác nhauinput một giá trị có thể nhận được.

Nhược điểm của việc sử dụng 'setInterval' dường như không áp dụng trong trường hợp này:

  • Độ trễ 100ms? Đối với nhiều ứng dụng, 100ms là đủ nhanh.
  • Đã thêm tải trên trình duyệt? Nói chung, việc thêm nhiều tập hợp nặng trên trang của bạn là không tốt. Nhưng trong trường hợp cụ thể này, tải trang được thêm vào là không thể phát hiện được.
  • Nó không mở rộng ra nhiều đầu vào? Hầu hết các trang không có nhiều hơn một số đầu vào, mà bạn có thể đánh hơi tất cả trong cùng một setInterval.

21
Đây dường như là cách duy nhất để phát hiện các thay đổi đối với trường đầu vào trong một biểu mẫu khi sử dụng trình duyệt Nintendo 3DS (Phiên bản / 1.7552.EU).
Johan

4
Lưu ý: Quá tải có thể được giảm bớt. Nếu bạn bắt đầu setInterval khi đầu vào được lấy nét và xóaInterval khi đầu vào bị mất tiêu điểm
Tebe

10
Tại sao bạn sẽ tạo một khoảng thời gian 100ms chạy liên tục mà không có lý do gì để nó liên tục chạy? SỰ KIỆN người. Sử dụng chúng.
Gavin

15
@Gavin, trong trường hợp cụ thể này, JS thiếu các sự kiện .. hãy tìm cho chúng tôi một tập hợp các sự kiện có thể nhận ra, đầu vào của người dùng, dán người dùng, cắt giảm người dùng, chèn javascript, xóa javascript, tự động hoàn thành biểu mẫu, biểu mẫu ẩn, không hiển thị các hình thức.
Naramsim

2
@Gavin JS dường như không có một sự kiện trao đổi nào được kích hoạt MỌI THỨ một đầu vào được thay đổi. (chỉ cần làm một tài liệu.getEuityById (tên) .value = Math.random ()) để xem không có giải pháp kích hoạt sự kiện nào hoạt động.
Joeri

58

Liên kết với oninput sự kiện dường như hoạt động tốt trong hầu hết các trình duyệt lành mạnh. IE9 cũng hỗ trợ nó, nhưng việc triển khai bị lỗi (sự kiện không được kích hoạt khi xóa các ký tự).

Với jQuery phiên bản 1.7+, onphương thức này rất hữu ích để liên kết với sự kiện như thế này:

$(".inputElement").on("input", null, null, callbackFunction);

12
oninputsự kiện không hoạt động với input[type=reset]hoặc chỉnh sửa javascript như bạn có thể thấy trong thử nghiệm này: codepen.io/yukulele/pen/xtEpb
Yukulélé

2
@ Yukulélé, Ít nhất chúng ta có thể làm việc xung quanh điều đó dễ dàng hơn là cố gắng phát hiện tất cả hành động có thể có của người dùng .
Pacerier

30

Câu trả lời năm 2017 : sự kiện đầu vào thực hiện chính xác điều này cho bất kỳ điều gì gần đây hơn IE8.

$(el).on('input', callback)

6
Xin lỗi nhưng ... nó khác với câu trả lời năm 2012 của HRJ ở trên như thế nào? Dù sao, inputsự kiện là không phát hiện ra các thay đổi JS.
David

16

Thật không may, không có sự kiện hoặc tập hợp các sự kiện phù hợp với tiêu chí của bạn. Nhấn phím và sao chép / dán có thể được xử lý vớikeyup sự kiện này. Thay đổi thông qua JS là khó khăn hơn. Nếu bạn có quyền kiểm soát mã đặt hộp văn bản, cách tốt nhất của bạn là sửa đổi nó để gọi trực tiếp chức năng của bạn hoặc kích hoạt sự kiện người dùng trên hộp văn bản:

// Compare the textbox's current and last value.  Report a change to the console.
function watchTextbox() {
  var txtInput = $('#txtInput');
  var lastValue = txtInput.data('lastValue');
  var currentValue = txtInput.val();
  if (lastValue != currentValue) {
    console.log('Value changed from ' + lastValue + ' to ' + currentValue);
    txtInput.data('lastValue', currentValue);
  }
}

// Record the initial value of the textbox.
$('#txtInput').data('lastValue', $('#txtInput').val());

// Bind to the keypress and user-defined set event.
$('#txtInput').bind('keypress set', null, watchTextbox);

// Example of JS code triggering the user event
$('#btnSetText').click(function (ev) {
  $('#txtInput').val('abc def').trigger('set');
});

Nếu bạn không có quyền kiểm soát mã đó, bạn có thể sử dụng setInterval() để 'xem' hộp văn bản để thay đổi:

// Check the textbox every 100 milliseconds.  This seems to be pretty responsive.
setInterval(watchTextbox, 100);

Kiểu giám sát hoạt động này sẽ không bắt kịp cập nhật 'ngay lập tức', nhưng dường như nó đủ nhanh để không có độ trễ có thể nhận biết được. Như DrLouie đã chỉ ra trong các bình luận, giải pháp này có thể không mở rộng tốt nếu bạn cần xem nhiều đầu vào. Bạn luôn có thể điều chỉnh tham số thứ 2 setInterval()để kiểm tra thường xuyên hơn hoặc ít hơn.


FYI thực sự có một loạt các sự kiện có thể được kết hợp để phù hợp với tiêu chí của OP ở các mức độ khác nhau trên các trình duyệt (xem các liên kết trong bình luận câu hỏi đầu tiên). Câu trả lời này không sử dụng bất kỳ sự kiện nào đã nói và trớ trêu thay có lẽ sẽ hoạt động tốt như vậy trong tất cả các trình duyệt, mặc dù có độ trễ nhẹ;)
Crescent Fresh

OP muốn nắm bắt các thay đổi đối với hộp văn bản thông qua JavaScript (ví dụ: myTextBox.value = 'foo';Không có sự kiện JavaScript nào xử lý tình huống đó.
Annabelle

1
Điều gì xảy ra nếu ai đó có 50 trường để giữ các tab trên?
DoctorLouie

1
Có, tôi chỉ có 1 trường trong trường hợp của mình, nhưng tôi không hiểu tại sao điều này sẽ không hoạt động tốt cho một số lĩnh vực. Có lẽ sẽ hiệu quả nhất khi chỉ có 1 setTimeout kiểm tra tất cả các đầu vào.
Dustin Boswell

1
@Doumund: Không có sự kiện JavaScript nào xử lý tình huống đó - Khắc phục: IE có thể xử lý nó input.onpropertychangevà FF2 +, Opera 9.5, Safari 3 và Chrome 1 có thể xử lý nó input.__defineSetter__('value', ...)(mặc dù nó được ghi là không hoạt động trên các nút DOM, tôi có thể xác minh nó hoạt động). Sự khác biệt duy nhất từ ​​việc triển khai của IE là IE kích hoạt trình xử lý không chỉ trên cài đặt lập trình mà còn trong các sự kiện chính.
Lưỡi liềm tươi

6

Đây là một giải pháp hơi khác nếu bạn không thích bất kỳ câu trả lời nào khác:

var field_selectors = ["#a", "#b"];
setInterval(function() { 
  $.each(field_selectors, function() { 
    var input = $(this);
    var old = input.attr("data-old-value");
    var current = input.val();
    if (old !== current) { 
      if (typeof old != 'undefined') { 
        ... your code ...
      }
      input.attr("data-old-value", current);
    }   
  }   
}, 500);

Hãy xem xét rằng bạn không thể dựa vào nhấp chuột và gõ phím để chụp trình đơn ngữ cảnh.


Câu trả lời này làm việc tốt nhất cho tôi. Tôi đã gặp một số vấn đề với bộ chọn của mình cho đến khi tôi sử dụng: $("input[id^=Units_]").each(function() {
robr

4

Thêm mã này ở đâu đó, điều này sẽ thực hiện các mẹo.

var originalVal = $.fn.val;
$.fn.val = function(){
    var result =originalVal.apply(this,arguments);
    if(arguments.length>0)
        $(this).change(); // OR with custom event $(this).trigger('value-changed');
    return result;
};

Tìm thấy giải pháp này tại val () không kích hoạt thay đổi () trong jQuery


3

Tôi đã tạo ra một mẫu. Có thể nó sẽ làm việc cho bạn.

var typingTimer;
var doneTypingInterval = 10;
var finaldoneTypingInterval = 500;

var oldData = $("p.content").html();
$('#tyingBox').keydown(function () {
    clearTimeout(typingTimer);
    if ($('#tyingBox').val) {
        typingTimer = setTimeout(function () {
            $("p.content").html('Typing...');
        }, doneTypingInterval);
    }
});

$('#tyingBox').keyup(function () {
    clearTimeout(typingTimer);
    typingTimer = setTimeout(function () {
        $("p.content").html(oldData);
    }, finaldoneTypingInterval);
});


<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>


<textarea id="tyingBox" tabindex="1" placeholder="Enter Message"></textarea>
<p class="content">Text will be replace here and after Stop typing it will get back</p>

http://jsfiddle.net/utbh575s/


3

Chúng tôi thực sự không cần thiết lập các vòng lặp để phát hiện các thay đổi javaScript. Chúng tôi đã thiết lập nhiều trình lắng nghe sự kiện cho phần tử mà chúng tôi muốn phát hiện. chỉ cần kích hoạt bất kỳ sự kiện không có hại sẽ làm cho công việc.

$("input[name='test-element']").on("propertychange change click keyup input paste blur", function(){
console.log("yeh thats worked!");
});

$("input[name='test-element']").val("test").trigger("blur");

và ofc điều này chỉ khả dụng nếu bạn có toàn quyền kiểm soát các thay đổi javascript trong dự án của bạn.


2

Chà, cách tốt nhất là bao gồm ba căn cứ mà bạn tự liệt kê. Một đơn giản: onblur ,: onkeyup, v.v. sẽ không hoạt động cho những gì bạn muốn, vì vậy chỉ cần kết hợp chúng.

KeyUp sẽ bao gồm hai cái đầu tiên và nếu Javascript đang sửa đổi hộp đầu vào, tôi chắc chắn hy vọng đó là javascript của riêng bạn, vì vậy chỉ cần thêm một cuộc gọi lại trong chức năng sửa đổi nó.


1
+1 cho giải pháp đơn giản, mặc dù có thể OP không thể / không muốn sửa đổi mã thực hiện thay đổi cho hộp văn bản.
Annabelle

Việc liệt kê tất cả các sự kiện có thể không có vẻ mạnh mẽ đối với tôi. Keyup có hoạt động không nếu người dùng nhấn xóa (tức là phím lặp lại)? Điều gì về tự động hoàn thành (hoặc thanh công cụ tự động điền giá trị)? Hoặc có những nguồn đầu vào đặc biệt không kích hoạt phím nhấn? Tôi lo lắng rằng sẽ có một cái gì đó như thế này mà bạn sẽ bỏ lỡ.
Dustin Boswell

1

Đây là một ví dụ hoạt động mà tôi đang sử dụng để thực hiện một biến thể tự động hoàn thành, chọn một bộ chọn jqueryui (danh sách), nhưng tôi không muốn nó hoạt động chính xác như tự động hoàn thành jqueryui có menu thả xuống.

$("#tagFilter").on("change keyup paste", function() {
     var filterText = $("#tagFilter").val();
    $("#tags").empty();
    $.getJSON("http://localhost/cgi-bin/tags.php?term=" + filterText,
        function(data) {
            var i;
            for (i = 0; i < data.length; i++) {
                var tag = data[i].value;
                $("#tags").append("<li class=\"tag\">" + tag + "</li>");
            }
        }); 
});

1

KHÔNG CÓ YÊU CẦU! (Dù sao nó cũng lỗi thời ngày nay)

Chỉnh sửa: Tôi đã xóa các sự kiện HTML. KHÔNG sử dụng các sự kiện HTML ... thay vào đó hãy sử dụng Trình nghe sự kiện Javascript.

document.querySelector("#testInput").addEventListener("input", test);

function test(e) {
 var a = document.getElementById('output');
 var b = /^[ -~]+$/;
 if (e.target.value == '' || b.test(e.target.value)) {
  a.innerText = "Text is Ascii?.. Yes";
 } else if (!b.test(e.target.value)) {
  a.innerText = "Text is Ascii?.. No";
 }
}
Try pressing Alt+NumPad2+NumPad3 in the input, it will instantly detect a change, whether you Paste, Type, or any other means, rather than waiting for you to unselect the textbox for changes to detect.

<input id="testInput">
<br>
<a id="output">Text is Ascii?.. Yes</a>


0

Bạn có thể chỉ sử dụng <span contenteditable="true" spellcheck="false">yếu tố thay cho <input type="text">?

<span>(với contenteditable="true" spellcheck="false"các thuộc tính) phân biệt <input>chủ yếu bởi vì:

  • Nó không được tạo kiểu như một <input>.
  • Nó không có thuộc valuetính, nhưng văn bản được hiển thị như là innerTextmột phần của cơ thể bên trong của nó.
  • Đó là multiline trong khi <input>không phải mặc dù bạn đặt thuộc tính multiline="true".

Tất nhiên, để hoàn thành giao diện, bạn có thể định kiểu nó bằng CSS, trong khi viết giá trị là innerText bạn có thể nhận cho nó một sự kiện:

Đây là một câu đố .

Thật không may, có một cái gì đó không thực sự hoạt động trong IE và Edge, mà tôi không thể tìm thấy.


Tôi nghĩ rằng có những lo ngại về khả năng tiếp cận xung quanh việc sử dụng phương pháp đó.
Daniel Tonon

0

Mặc dù câu hỏi này đã được đăng 10 năm trước, tôi tin rằng nó vẫn cần một số cải tiến. Vì vậy, đây là giải pháp của tôi.

$(document).on('propertychange change click keyup input paste', 'selector', function (e) {
    // Do something here
});

Vấn đề duy nhất với giải pháp này là, nó sẽ không kích hoạt nếu giá trị thay đổi từ javascript như thế nào $('selector').val('some value'). Bạn có thể kích hoạt bất kỳ sự kiện nào cho bộ chọn của mình khi bạn thay đổi giá trị từ javascript.

$(selector).val('some value');
// fire event
$(selector).trigger('change');

-2

bạn có thể xem ví dụ này và chọn những sự kiện mà bạn quan tâm:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
<title>evetns</title>
</head>
<body>
<form>
    <input class="controlevents" id="i1" type="text" /><br />
    <input class="controlevents" id="i2" type="text" /><br />
    <input class="controlevents" id="i3" type="text" /><br />
    <input class="controlevents" id="i4" type="text" /><br />
    <input class="controlevents" id="i5" type="text" /><br />
</form>
<div id="datatext"></div>
</body>
</html>
<script>
$(function(){

function testingevent(ev){
    if (ev.currentTarget.tagName=="INPUT")
        $("#datatext").append("<div>id : " + ev.currentTarget.id + ", tag: " + ev.currentTarget.tagName + ", type: "+ ev.type +"</div>");
}   

    var eventlist = ["resizeend","rowenter","dragleave","beforepaste","dragover","beforecopy","page","beforeactivate","beforeeditfocus","controlselect","blur",
                    "beforedeactivate","keydown","dragstart","scroll","propertychange","dragenter","rowsinserted","mouseup","contextmenu","beforeupdate",
                    "readystatechange","mouseenter","resize","copy","selectstart","move","dragend","rowexit","activate","focus","focusin","mouseover","cut",
                    "mousemove","focusout","filterchange","drop","blclick","rowsdelete","keypress","losecapture","deactivate","datasetchanged","dataavailable",
                    "afterupdate","mousewheel","keyup","movestart","mouseout","moveend","cellchange","layoutcomplete","help","errorupdate","mousedown","paste",
                    "mouseleave","click","drag","resizestart","datasetcomplete","beforecut","change","error","abort","load","select"];

    var inputs = $(".controlevents");

    $.each(eventlist, function(i, el){
        inputs.bind(el, testingevent);
    });

});
</script>

4
Tôi nghĩ bạn đã quên một loại sự kiện :)
Dustin Boswell

-3

Tôi có thể đến bữa tiệc muộn ở đây nhưng bạn có thể không chỉ sử dụng sự kiện .change () mà jQuery cung cấp.

Bạn sẽ có thể làm một cái gì đó như ...

$(#CONTROLID).change(function(){
    do your stuff here ...
});

Bạn luôn có thể liên kết nó với một danh sách các điều khiển với thứ gì đó như ...

var flds = $("input, textarea", window.document);

flds.live('change keyup', function() {
    do your code here ...
});

Chất kết dính trực tiếp đảm bảo rằng tất cả các yếu tố tồn tại trên trang hiện tại và trong tương lai đều được xử lý.


2
Sự kiện thay đổi chỉ kích hoạt sau khi mất tiêu điểm, vì vậy nó không kích hoạt trong khi người dùng đang gõ vào hộp, chỉ sau khi họ hoàn thành và tiếp tục làm việc khác.
Eli Sand

2
Giống như nhiều câu trả lời khác ở đây, điều này sẽ không hoạt động khi giá trị của phần tử được sửa đổi từ Javascript. Tôi không biết liệu nó có bỏ lỡ bất kỳ trường hợp sửa đổi nào khác mà OP yêu cầu hay không.
Đánh dấu Amery

-4

Đây là cách nhanh nhất và sạch nhất để làm điều đó:

Tôi đang sử dụng Jquery ->

$('selector').on('change', function () {
    console.log(this.id+": "+ this.value);
});

Nó đang làm việc khá tốt cho tôi.


7
Điều này đã được đề xuất. Nó chỉ giải quyết các trường hợp đơn giản, khi người dùng gõ văn bản.
Barshe
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.