【问题标题】:How to detect programmatic value change on input field如何检测输入字段上的编程值变化
【发布时间】:2024-01-31 06:05:01
【问题描述】:

我已经阅读了几个关于此主题的问题[1][2][3],但似乎没有一个问题可以为这个问题提供通用解决方案。所有答案似乎都针对某些特定情况。

我有这个简单的输入框

<input type="number" id="inputBox" min="0" max="255" step="1" />

我对其进行了严格的输入验证:

inputBox.addEventListener("input", function () {
    validateInput(this);
});

inputBox.addEventListener("keydown", function (e) {
    validateInput(this, e);
});

function validateInput(elm, e) {
    // handle keydown event
    if (e) {
        // do not allow floating-point numbers, if it's not expected
        if (!isFloat(elm.step)) {
            if (e.key == ".") {
                e.preventDefault();
            }
        }
    }
    // handle input event
    else {
        // do not allow leading zeros
        while (elm.value.length > 1 && elm.value[0] === "0") {
            elm.value = elm.value.toString().slice(1);
        }
        // input should be between min and max
        if (elm.validity.rangeUnderflow) {
            elm.value = elm.min;
        }
        else if (elm.validity.rangeOverflow) {
            elm.value = elm.max;
        }
    }
}

对于用户输入来说,所有这些似乎都可以正常工作。

var inputBox = document.getElementById("inputBox");

inputBox.addEventListener("input", function() {
  validateInput(this);
});

inputBox.addEventListener("keydown", function(e) {
  validateInput(this, e);
});

function validateInput(elm, e) {
  // handle keydown event
  if (e) {
    // do not allow floating-point numbers, if it's not expected
    if (!isFloat(elm.step)) {
      if (e.key == ".") {
        e.preventDefault();
      }
    }
  }
  // handle input event
  else {
    // do not allow leading zeros
    while (elm.value.length > 1 && elm.value[0] === "0") {
      elm.value = elm.value.toString().slice(1);
    }
    // input should be between min and max
    if (elm.validity.rangeUnderflow) {
      elm.value = elm.min;
    } else if (elm.validity.rangeOverflow) {
      elm.value = elm.max;
    }
  }
}

function isFloat(f) {
  var f = parseFloat(f);
  var floor = Math.floor(f);
  var fraction = f - floor;
  if (fraction > 0) {
    return true;
  }
  return false;
}
&lt;input type="number" id="inputBox" min="0" max="255" step="1" /&gt;

但用户仍然可以通过编程方式修改输入字段值。用户可以通过控制台输入以下值来绕过验证,这些是无效/意外的值:

inputBox.value = "005";
inputBox.value = "2.5"
inputBox.value = "-05.5";

如果用户使用inputBox.value 更改字段值,则理想的解决方案是调用函数(例如validateProgrammaticInput())。

inputBox.value = -10; // magically call validateProgrammaticInput()

注意:我没有使用表单。没有提交按钮。这不会被发送到服务器。这是一个客户端应用程序。应实时验证价值。如果想以编程方式修改字段值,我可以在我的代码中触发自定义事件来验证输入,但事实并非如此。我想要的是验证输入,如果用户以编程方式输入它。所以我的用例与问题无关。我想我应该在混淆之前指出这些。

【问题讨论】:

  • 你可以为inputBox.value定义setter,所以它会调用你的函数。
  • @IvanShmidt 你能提供一个可行的例子吗?也许是JSFiddle
  • @IvanShmidt 我认为这不会有帮助。这仅允许编程输入。如果我通过 UI 在字段中输入数字,则无法使用 inputBox.value 获取输入的值,因为重新定义 value 属性会破坏输入字段的行为。
  • jsfiddle.net/4wfjk1hh/2 - 以编程方式和通过 UI 工作

标签: javascript html validation input event-handling


【解决方案1】:

您可以在像这样更改值后以编程方式触发事件

var inputBox = document.getElementById("inputBox");
inputBox.addEventListener("input", function () {
  console.log("input");
    // input should be between min and max
    if (this.validity.rangeUnderflow) {
        this.value = this.min;
    }
    else if (this.validity.rangeOverflow) {
        this.value = this.max;
    }
    // do not allow leading zeros
    while (this.value.length > 1 && this.value.toString()[0] === "0") {
        this.value = this.value.toString().slice(1);
    }
});

inputBox.addEventListener("keydown", function (e) {
    // do not allow floating-point numbers, if it's not expected
    if (!isFloat(this.step)) {
        if (e.key == ".") {
            e.preventDefault();
        }
    }
},false);

function change(){
  inputBox.value = "005";
  inputBox.dispatchEvent(new Event('input'));
}

function isFloat(n){
    return Number(n) === n && n % 1 !== 0;
}
<input type="number" id="inputBox" min="0" max="255" step="1" />

<button onclick="change()">change</button>

【讨论】:

  • 请参阅我的问题底部的注释。
  • 不确定“用户以编程方式输入”是什么意思,但是,您可以使用 setInterval() 定期验证字段的值
  • 另外,您的isFloat() 函数,或者更确切地说是kennebec's,期望n 是一个数字。您不能直接使用它验证输入值(这是一个字符串)。请参阅此test。但是,mine 已准备好应对多种情况。
  • “用户以编程方式输入”意味着可以打开控制台并更改那里的值以绕过验证。
【解决方案2】:

所以,对我来说,您的事件侦听器根本不会被触发,因为它们没有发生。当以编程方式更改值时,字段上没有“keydown”,因为在 DOM 中没有触发任何事件。

对我来说,我认为您应该连接一些其他事件处理程序,以及更多“页面级别”。在查看 jQuery 事件类别 (https://api.jquery.com/category/events/) 时,如果您将这些事件分配给 page 本身 - 在鼠标 x\y 更改时,在 page 上输入\离开和焦点\模糊。

使用所有这些事件似乎有点过火,但这似乎是一个独特的案例。对我来说,你从不真正信任用户输入,所以我倾向于在用户提交时重新计算\验证数据,但对于这种数据没有提交给你的场景,我认为通过一些页面级事件触发这些项目而不是而不是输入特定事件可能会让你克服困难......

【讨论】:

    最近更新 更多