<input>
通过 JavaScript 代码更改元素值时的事件是什么?例如:
$input.value = 12;
该input
事件在此不帮助,因为它不是谁在改变值的用户。
在 Chrome 上测试时,change
不会触发该事件。也许是因为元素没有失去焦点(它没有获得焦点,所以它不能失去焦点)?
<input>
通过 JavaScript 代码更改元素值时的事件是什么?例如:
$input.value = 12;
该input
事件在此不帮助,因为它不是谁在改变值的用户。
在 Chrome 上测试时,change
不会触发该事件。也许是因为元素没有失去焦点(它没有获得焦点,所以它不能失去焦点)?
没有内置事件。你至少有四个选择:
$input.value
代码时,请调用您希望由更改触发的代码其中,您会注意到#1、#3 和#4 都要求您在代码中做一些不同于$input.value = "new value";
轮询的事情,选项#2 是唯一一个可以处理value
直接设置的代码的选项。
细节:
最简单的解决方案:每当您更改$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 次/秒在现代系统,甚至是手机上都不是问题。
但是,投票仍然是一个丑陋的最后手段。
例子:
给自己一个函数来设置值并通知你,并使用该函数代替value
,结合input
事件处理程序来捕获用户的更改:
$input.setValue = function(newValue) {
this.value = newValue;
handleValueChange();
};
$input.addEventListener("input", handleValueChange, false);
用法:
$input.setValue("new value");
当然,您必须记住使用setValue
而不是分配给value
.
例子:
#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(支持defineProperty
DOM 元素,但不支持 JavaScript 对象)。当然,您需要在目标浏览器上对其进行测试。
但$input.val = ...
对于习惯于阅读普通 DOM 代码(或 jQuery 代码)的任何人来说,这似乎是一个错误。
在你问之前:不,你不能用上面的来替换value
属性本身。
例子:
基于@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);
}
我会根据 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);
不是更改特定输入元素的“值”属性,而是可以对所有输入元素进行一般更改:
Object.defineProperty(HTMLInputElement.prototype, "value", descriptor);
此方法仅适用于使用 javascript 更改值,例如 input.value="new value"。在输入框中键入新值时不起作用。
这是挂钩所有输入更改的 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);
})
}
}
});
用法示例:
document.getElementById("myInput").addInputChangedByJsListener(function() {
console.log("Input changed to \"" + this.value + "\"");
});
一种可能的策略是使用一个mutationObserver来检测属性的变化,如下所示:
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(){
console.log('hello')});
});
observer.observe($input, {
attributes: true
});
虽然这本身不会检测到如下变化:
$input.value = 12
它会检测到实际值属性的变化:
$input.setAttribute('value', 12)
因此,如果是您以编程方式设置值,只需确保更改value = 12
语句旁边的属性,您就可以获得所需的结果。