簡體   English   中英

使用 MutationObserver 檢測輸入值變化

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM