[英]Detect input value change with MutationObserver
我想检测输入字段中的文本/值何时更改。 即使我用 js 更改了值,我也想检测该更改。
这是我迄今为止在 fiddle 的演示中尝试过的。
HTML :
<input type="text" id="exNumber"/>
JavaScript :
var observer = new MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
// console.log('Mutation type: ' + mutation.type);
if ( mutation.type == 'childList' ) {
if (mutation.addedNodes.length >= 1) {
if (mutation.addedNodes[0].nodeName != '#text') {
// console.log('Added ' + mutation.addedNodes[0].tagName + ' tag.');
}
}
else if (mutation.removedNodes.length >= 1) {
// console.log('Removed ' + mutation.removedNodes[0].tagName + ' tag.')
}
}
if (mutation.type == 'attributes') {
console.log('Modified ' + mutation.attributeName + ' attribute.')
}
});
});
var observerConfig = {
attributes: true,
childList: false,
characterData: false
};
// Listen to all changes to body and child nodes
var targetNode = document.getElementById("exNumber");
observer.observe(targetNode, observerConfig);
要了解正在发生的事情,有必要弄清楚属性(内容属性)和属性(IDL 属性)之间的区别。 我不会对此进行扩展,因为在 SO 中已经有很好的答案涵盖了该主题:
当您通过输入或通过 JS 更改input
元素的内容时:
targetNode.value="foo";
浏览器更新value
属性而不是value
属性(它反映的是defaultValue
属性)。
然后,如果我们查看MutationObserver的规范,我们将看到属性是可以使用的对象成员之一。 因此,如果您明确设置value
属性:
targetNode.setAttribute("value", "foo");
MutationObserver 将通知属性修改。 但是规范列表中没有类似的属性:无法观察到value
属性。
如果要检测用户何时更改了 input 元素的内容,则input
事件是最直接的方法。 如果您需要捕获 JS 修改,请使用setInterval
并将新值与旧值进行比较。
检查此SO 问题以了解不同的替代方案及其局限性。
我稍微修改了Shawn 的方法,想分享一下。 无法相信实际上有解决方案。
在输入框中键入以查看默认行为。 现在,打开 DevTools 并选择 input 元素,然后更改其值,例如$0.value = "hello"
。 检查 UI 与 API 的区别。 似乎 UI 交互不会直接修改value
属性。 如果是,它也会记录"...changed via API..."
。
let inputBox = document.querySelector("#inputBox"); inputBox.addEventListener("input", function () { console.log("Input value changed via UI. New value: '%s'", this.value); }); observeElement(inputBox, "value", function (oldValue, newValue) { console.log("Input value changed via API. Value changed from '%s' to '%s'", oldValue, newValue); }); function observeElement(element, property, callback, delay = 0) { let elementPrototype = Object.getPrototypeOf(element); if (elementPrototype.hasOwnProperty(property)) { let descriptor = Object.getOwnPropertyDescriptor(elementPrototype, property); Object.defineProperty(element, property, { get: function() { return descriptor.get.apply(this, arguments); }, set: function () { let oldValue = this[property]; descriptor.set.apply(this, arguments); let newValue = this[property]; if (typeof callback == "function") { setTimeout(callback.bind(this, oldValue, newValue), delay); } return newValue; } }); } }
<input type="text" id="inputBox" placeholder="Enter something" />
可以观察到value 属性,不要浪费时间。
function changeValue (event, target) { document.querySelector("#" + target).value = new Date().getTime(); } function changeContentValue () { document.querySelector("#content").value = new Date().getTime(); } Object.defineProperty(document.querySelector("#content"), "value", { set: function (t) { alert('#changed content value'); var caller = arguments.callee ? (arguments.callee.caller ? arguments.callee.caller : arguments.callee) : '' console.log('this =>', this); console.log('event => ', event || window.event); console.log('caller => ', caller); return this.textContent = t; } });
<form id="form" name="form" action="test.php" method="post"> <input id="writer" type="text" name="writer" value="" placeholder="writer" /> <br /> <textarea id="content" name="content" placeholder="content" ></textarea> <br /> <button type="button" >Submit (no action)</button> </form> <button type="button" onClick="changeValue(this, 'content')">Change Content</button>
这有效并保留和链接原始的 setter 和 getter,因此有关您的领域的所有其他内容仍然有效。
var registered = [];
var setDetectChangeHandler = function(field) {
if (!registered.includes(field)) {
var superProps = Object.getPrototypeOf(field);
var superSet = Object.getOwnPropertyDescriptor(superProps, "value").set;
var superGet = Object.getOwnPropertyDescriptor(superProps, "value").get;
var newProps = {
get: function() {
return superGet.apply(this, arguments);
},
set: function (t) {
var _this = this;
setTimeout( function() { _this.dispatchEvent(new Event("change")); }, 50);
return superSet.apply(this, arguments);
}
};
Object.defineProperty(field, "value", newProps);
registered.push(field);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.