javascript - 捕获 HTML 输入元素值的所有更改的现代方法是什么?

标签 javascript html

是否有一种标准方法可以捕获 HTML 输入元素值的所有更改,无论它是由用户输入更改还是以编程方式更改?

考虑以下代码(纯粹出于示例目的,并未采用良好的编码实践编写,您可以将其视为恰好能够在某些网络浏览器中运行的伪代码:P)

<!DOCTYPE html>
<html>
<head>
    <title>Test Page</title>
    <script>
        window.onload = () => {
            var test = document.getElementById("test");

            test.onchange = () => {
                console.log("OnChange Called");
                console.log(test.value);
            }  // Called when the input element loses focus and its value changed

            test.oninput = () => {
                console.log("OnInput Called");
                console.log(test.value);
            }  // Called whenever the input value changes

            test.onkeyup = () => {
                console.log("OnKeyUp Called");
                console.log(test.value);
            }  // some pre-HTML5 way of getting real-time input value changes
        }
    </script>
</head>
<body>
    <input type="text" name="test" id="test">
</body>
</html>

但是,当以编程方式更改输入元素的值时,这些事件都不会触发,就像有人执行

document.getElementById("test").value = "Hello there!!";

要捕获以编程方式更改的值,过去通常可以执行以下两种操作之一:

1) 告诉编码人员每次以编程方式更改输入值时手动触发 onchange 事件,例如

document.getElementById("test").value = "Hello there!!";
document.getElementById("test").onchange();

但是,对于手头的这个项目,客户不会接受这种解决方案,因为他们有许多来来去去的承包商/分包商,我猜他们只是不相信他们的承包商会严格遵守这种规则,更重要的是,他们从之前的契约(Contract)中得到了一个可行的解决方案,这是第二种旧的做事方式

2)设置一个计时器,定期检查输入元素值并在其更改时调用函数,如下所示

        var pre_value = test.value;

        setInterval(() => {
            if (test.value !== pre_value) {
                console.log("Value changed");
                console.log(test.value);
                pre_value = test.value;
            }
        }, 200);  // checks the value every 200ms and see if it's changed

这看起来像是 jQuery v1.6 时代的恐龙,恕我直言,由于各种原因,这相当糟糕,但不知何故适合客户的要求。

现在已经是 2019 年了,我想知道是否有一些现代的方法来替换上述代码? JavaScript setter/getter 看起来很有前途,但是当我尝试以下代码时,它只是破坏了 HTML 输入元素

        Object.defineProperty(test, "value", {
            set: v => {
                this.value = v;
                console.log("Setter called");
                console.log(test.value);
            },
            get: ()=> {
                console.log("Getter called");
                return this.value;
            }
        });

当以编程方式分配 test.value 时,将调用 setter 函数,但 HTML 页面上的输入元素会以某种方式被破坏。

那么,除了古老的“使用轮询计时器”方法之外,您是否知道如何捕获 HTML 输入元素值的所有更改并调用处理函数?

注意:请注意,这里的所有代码仅用于示例目的,不应在实际系统中使用,最好使用 addEventListener/attachEvent/dispatchEvent/fireEvent 等方法

最佳答案

要观察对元素的 .value 的赋值和检索,Object.defineProperty 是可行的方法,但您需要调用原始 自定义方法中的 setter 和 getter 函数,可在 HTMLInputElement.prototype 上找到:

const { getAttribute, setAttribute } = test;
test.setAttribute = function(...args) {
  if (args[0] === 'value') {
    console.log('Setting value');
  }
  return setAttribute.apply(this, args);
};
test.getAttribute = function(...args) {
  if (args[0] === 'value') {
    console.log('Getting value');
  }
  return getAttribute.apply(this, args);
};



test.setAttribute('value', 'foo');
console.log(test.getAttribute('value'));
<input type="text" name="test" id="test">

注意使用方法而不是箭头函数 - 这很重要,它允许保留 this 上下文。 (您也可以使用诸如 set.call(input, v) 之类的方法,但这不太灵活)

这仅适用于对 .value 的更改。如果你愿意,你可以为 setAttribute('value) 打上类似的代码:

const { setAttribute } = test;
test.setAttribute = function(...args) {
  if (args[0] === 'value') {
    console.log('attribute set!');
  }
  return setAttribute.apply(this, args);
};

test.setAttribute('value', 'foo');
<input type="text" name="test" id="test">

关于javascript - 捕获 HTML 输入元素值的所有更改的现代方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55332114/

相关文章:

javascript - 如何从函数中设置 process.env?

javascript - 将 Canvas 转换为 HTML5 中固定大小的图像

javascript - 如何用标签包裹一组单词,JavaScript Replace Regular Expressions

html - Flexbox 元素不收缩

html - iOS 设备上的 MP4 浏览器内视频播放间歇性中断

javascript - 我可以将每个元素用于动态创建的元素吗?

javascript - 通过服务获取数据

jquery - 滚动覆盖 HTML 中的 div 元素

css - 当指定 100% 宽度时,div 不会一直延伸到页面末尾

html - 使用小窗口浏览器拉伸(stretch)背景