JavaScript 更改输入值时的事件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/42427606/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Event when input value is changed by JavaScript?
提问by pery mimon
What is the event when an <input>element's value is changed via JavaScript code? For example:
<input>通过 JavaScript 代码更改元素值时的事件是什么?例如:
$input.value = 12;
The inputevent is not helping here because it's not the user who is changing the value.
该input事件在此不帮助,因为它不是谁在改变值的用户。
When testing on Chrome, the changeevent isn't fired. Maybe because the element didn't lose focus (it didn't gain focus, so it can't lose it)?
在 Chrome 上测试时,change不会触发该事件。也许是因为元素没有失去焦点(它没有获得焦点,所以它不能失去焦点)?
采纳答案by foxontherock
Based on @t-j-crowder and @maciej-swist answers, let's add this one, with ".apply" function that prevent infinite loop without redefining the object.
基于@tj-crowder 和@maciej-swist 的答案,让我们添加这个,使用“.apply”函数防止无限循环而不重新定义对象。
function customInputSetter(){
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
var originalSet = descriptor.set;
// define our own setter
descriptor.set = function(val) {
console.log("Value set", this, val);
originalSet.apply(this,arguments);
}
Object.defineProperty(HTMLInputElement.prototype, "value", descriptor);
}
回答by T.J. Crowder
There is no built-in event for that. You have at least four choices:
没有内置事件。你至少有四个选择:
- Any time you change
$input.valuein code, call the code you want triggered by the change - Poll for changes
- Give yourself a method you use to change the value, which will also do notifications
- (Variant of #3) Give yourself a propertyyou use to change the value, which will also do notifications
- 每当您更改
$input.value代码时,请调用您希望由更改触发的代码 - 投票更改
- 给自己一个你用来改变值的方法,它也会做通知
- (#3 的变体)给自己一个用于更改值的属性,该属性也将发出通知
Of those, you'll note that #1, #3, and #4 all require that you do something in your code differently from just $input.value = "new value";Polling, option #2, is the only one that will work with code that just sets valuedirectly.
其中,您会注意到#1、#3 和#4 都要求您在代码中做一些不同于$input.value = "new value";轮询的事情,选项#2 是唯一一个可以处理value直接设置的代码的选项。
Details:
细节:
The simplest solution: Any time you change
$input.valuein code, call the code you want triggered by the change:$input.value = "new value"; handleValueChange();Poll for changes:
var last$inputValue = $input.value; setInterval(function() { var newValue = $input.value; if (last$inputValue != newValue) { last$inputValue = newValue; handleValueChange(); } }, 50); // 20 times/secondPolling has a bad reputation (for good reasons), because it's a constant CPU consumer. Modern browsers dial down timer events (or even bring them to a stop) when the tab doesn't have focus, which mitigates that a bit. 20 times/second isn't an issue on modern systems, even mobiles.
But still, polling is an ugly last resort.
Example:
var $input = document.getElementById("$input"); var last$inputValue = $input.value; setInterval(function() { var newValue = $input.value; if (last$inputValue != newValue) { last$inputValue = newValue; handleValueChange(); } }, 50); // 20 times/second function handleValueChange() { console.log("$input's value changed: " + $input.value); } // Trigger a change setTimeout(function() { $input.value = "new value"; }, 800);<input type="text" id="$input">Give yourself a function to set the value and notify you, and use that function instead of
value, combined with aninputevent handler to catch changes by users:$input.setValue = function(newValue) { this.value = newValue; handleValueChange(); }; $input.addEventListener("input", handleValueChange, false);Usage:
$input.setValue("new value");Naturally, you have to remember to use
setValueinstead of assigning tovalue.Example:
var $input = document.getElementById("$input"); $input.setValue = function(newValue) { this.value = newValue; handleValueChange(); }; $input.addEventListener("input", handleValueChange, false); function handleValueChange() { console.log("$input's value changed: " + $input.value); } // Trigger a change setTimeout(function() { $input.setValue("new value"); }, 800);<input type="text" id="$input">A variant on #3: Give yourself a different propertyyou can set (again combined with an event handler for user changes):
Object.defineProperty($input, "val", { get: function() { return this.value; }, set: function(newValue) { this.value = newValue; handleValueChange(); } }); $input.addEventListener("input", handleValueChange, false);Usage:
$input.val = "new value";This works in all modern browsers, even old Android, and even IE8 (which supports
definePropertyon DOM elements, but not JavaScript objects in general). Of course, you'd need to test it on your target browsers.But
$input.val = ...looks like an error to anyone used to reading normal DOM code (or jQuery code).Before you ask: No, you can't use the above to replace the
valueproperty itself.Example:
var $input = document.getElementById("$input"); Object.defineProperty($input, "val", { get: function() { return this.value; }, set: function(newValue) { this.value = newValue; handleValueChange(); } }); $input.addEventListener("input", handleValueChange, false); function handleValueChange() { console.log("$input's value changed: " + $input.value); } // Trigger a change setTimeout(function() { $input.val = "new value"; }, 800);<input type="text" id="$input">
最简单的解决方案:每当您更改
$input.value代码时,调用您希望由更改触发的代码:$input.value = "new value"; handleValueChange();投票更改:
var last$inputValue = $input.value; setInterval(function() { var newValue = $input.value; if (last$inputValue != newValue) { last$inputValue = newValue; handleValueChange(); } }, 50); // 20 times/second轮询的名声很差(有充分的理由),因为它是一个持续的 CPU 消耗者。当标签没有焦点时,现代浏览器拨打定时器事件(甚至将它们带到停止),这会减轻一点。20 次/秒在现代系统甚至移动设备上都不是问题。
但是,投票仍然是一个丑陋的最后手段。
例子:
var $input = document.getElementById("$input"); var last$inputValue = $input.value; setInterval(function() { var newValue = $input.value; if (last$inputValue != newValue) { last$inputValue = newValue; handleValueChange(); } }, 50); // 20 times/second function handleValueChange() { console.log("$input's value changed: " + $input.value); } // Trigger a change setTimeout(function() { $input.value = "new value"; }, 800);<input type="text" id="$input">给自己一个函数来设置值并通知你,并使用该函数代替
value,结合input事件处理程序来捕获用户的更改:$input.setValue = function(newValue) { this.value = newValue; handleValueChange(); }; $input.addEventListener("input", handleValueChange, false);用法:
$input.setValue("new value");当然,您必须记住使用
setValue而不是分配给value.例子:
var $input = document.getElementById("$input"); $input.setValue = function(newValue) { this.value = newValue; handleValueChange(); }; $input.addEventListener("input", handleValueChange, false); function handleValueChange() { console.log("$input's value changed: " + $input.value); } // Trigger a change setTimeout(function() { $input.setValue("new value"); }, 800);<input type="text" id="$input">#3 的变体:给自己一个可以设置的不同属性(再次结合用户更改的事件处理程序):
Object.defineProperty($input, "val", { get: function() { return this.value; }, set: function(newValue) { this.value = newValue; handleValueChange(); } }); $input.addEventListener("input", handleValueChange, false);用法:
$input.val = "new value";这适用于所有现代浏览器,甚至旧的 Android,甚至 IE8(支持
definePropertyDOM 元素,但不支持 JavaScript 对象)。当然,您需要在目标浏览器上对其进行测试。但
$input.val = ...对于习惯于阅读普通 DOM 代码(或 jQuery 代码)的任何人来说,这似乎是一个错误。在你问之前:不,你不能用上面的来替换
value属性本身。例子:
var $input = document.getElementById("$input"); Object.defineProperty($input, "val", { get: function() { return this.value; }, set: function(newValue) { this.value = newValue; handleValueChange(); } }); $input.addEventListener("input", handleValueChange, false); function handleValueChange() { console.log("$input's value changed: " + $input.value); } // Trigger a change setTimeout(function() { $input.val = "new value"; }, 800);<input type="text" id="$input">
回答by Maciej Swist
I'd add a 5th option based on T.J. Crowder suggestions. But instead of adding new property You could change the actual "value" property to trigger additional action when set - either for the specific input element, or for all input objects:
我会根据 TJ Crowder 的建议添加第 5 个选项。但不是添加新属性,您可以更改实际的“值”属性以在设置时触发其他操作 - 无论是针对特定输入元素,还是针对所有输入对象:
//First store the initial descriptor of the "value" property:
var descriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
var inputSetter = descriptor.set;
//Then modify the "setter" of the value to notify when the value is changed:
descriptor.set = function(val) {
//changing to native setter to prevent the loop while setting the value
Object.defineProperty(this, "value", {set:inputSetter});
this.value = val;
//Custom code triggered when $input.value is set
console.log("Value set: "+val);
//changing back to custom setter
Object.defineProperty(this, "value", descriptor);
}
//Last add the new "value" descriptor to the $input element
Object.defineProperty($input, "value", descriptor);
Instead of changing the "value" property for specific input element, it can be changed generically for all input elements:
不是更改特定输入元素的“值”属性,而是可以对所有输入元素进行一般更改:
Object.defineProperty(HTMLInputElement.prototype, "value", descriptor);
This method works only for change of value with javascript e.g. input.value="new value". It doesn't work when keying in the new value in the input box.
此方法仅适用于使用 javascript 更改值,例如 input.value="new value"。在输入框中键入新值时不起作用。
回答by Kino101
Here is a solution to hook the value property changed for all inputs:
这是挂钩所有输入更改的 value 属性的解决方案:
var valueDescriptor = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, "value");
HTMLInputElement.prototype.addInputChangedByJsListener = function(cb) {
if(!this.hasOwnProperty("_inputChangedByJSListeners")) {
this._inputChangedByJSListeners = [];
}
this._inputChangedByJSListeners.push(cb);
}
Object.defineProperty(HTMLInputElement.prototype, "value", {
get: function() {
return valueDescriptor.get.apply(this, arguments);
},
set: function() {
var self = this;
valueDescriptor.set.apply(self, arguments);
if(this.hasOwnProperty("_inputChangedByJSListeners")){
this._inputChangedByJSListeners.forEach(function(cb) {
cb.apply(self);
})
}
}
});
Usage example:
用法示例:
document.getElementById("myInput").addInputChangedByJsListener(function() {
console.log("Input changed to \"" + this.value + "\"");
});
回答by Pabs123
One possible strategy is to use a mutationObserverto detect changes in attributes as follows:
一种可能的策略是使用mutationObserver来检测属性的变化,如下所示:
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(){
console.log('hello')});
});
observer.observe($input, {
attributes: true
});
Although this in itself will not detect a change like:
虽然这本身不会检测到如下变化:
$input.value = 12
it WILL detect a change of the actual value attribute:
它会检测到实际值属性的变化:
$input.setAttribute('value', 12)
So if it is you that is setting the value programatically, just be sure to alter the attribute alongside the value = 12statement and you can have the desired result.
因此,如果是您以编程方式设置值,只需确保更改value = 12语句旁边的属性,您就可以获得所需的结果。
回答by Marcelo Myara
I don't think there is an event that will cover all the programatically assigned scenarios for an input. But, I can tell you that you can programatically "fire" an event (a custom event, a regular event or just trigger an event handler[s])
我认为没有一个事件可以涵盖所有以编程方式分配的输入场景。但是,我可以告诉您,您可以以编程方式“触发”事件(自定义事件、常规事件或仅触发事件处理程序 [s])
It appears to me that you're using jQuery, and so, you could use:
在我看来,您正在使用 jQuery,因此,您可以使用:
$('input#inputId').val('my new value...').triggerHandler('change');
In that example, you're assigning a value, and forcing a call to the handler (or handlers) binded with the "change" event.
在该示例中,您正在分配一个值,并强制调用与“更改”事件绑定的处理程序(或多个处理程序)。

