如何通过忽略每次按键时的无效字符,使文本类型的输入元素只接受一个数值(十进制、正数和负数)?

How to make a text-type input-element accept just a numerical value (decimal, positive and negative) by ignoring invalid characters on each keypress?

我有一个 HTML 输入,这个输入只接受数字字符的字符串,

示例:

输入值:+0123.534534或-234234.543345或-13453,这些输入值有效。 字符 + 或 - 只存在一个并且在字符串值的第一个位置

我希望每个输入字符的输入值都应该保持当前有效的字符串,并将无效的输入字符替换为空字符

示例:

当我键入:+123.g ==> 值应立即替换 +123。 或者当我键入:g ==> 该值应立即替换为空值。

我找到了一个实现,但是缺少 (+/-/.) 字符

const getDigitsOnly = (value) => String(value).replace(NOT_NUMBERS, '');

这会做你想做的事

    let someString = "+123.g";
    let result = someString.replace(/[^0-9,+,-,.]+/g, "");
    console.log(result);

有关如何使用正则表达式的更多信息,请在此处查看 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions

这是我的解决方案。

我们向输入框添加了一个 input 事件侦听器,对于每个输入,我们都会格式化整个输入值。

注意:提交值时不要忘记trim尾随小数点(例如"123.""123") .

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

inputBox.addEventListener("input", () => {
  inputBox.value = format(inputBox.value);
});

function format(str) {
  if (!str.length) return str;

  str = str.replace(/[^.+-\d]/g, "");
  const firstChar = str.charAt(0);
  str = str.slice(1).replace(/[+-]/g, "");

  // Bug fix. Credit goes to @Peter Seliger
  // For pointing out the bug
  const charArray = [];
  let hasDecimalPoint = false;

  if (firstChar === ".") {
    if (!str.includes(".")) {
      hasDecimalPoint = true;
      charArray.push("0.");
    }
  } else charArray.push(firstChar);
  // End bug fix

  for (let i = 0; i < str.length; i++) {
    const char = str.charAt(i);

    if (char === ".") {
      if (hasDecimalPoint) continue;
      if (!i && firstChar !== "0") charArray.push("0");
      hasDecimalPoint = true;
    }

    charArray.push(char);
  }

  return charArray.join("");
}
<p>Enter your number here</p>
<input id="inputBox" type="text" />

格式化函数的算法。

1: If the input is empty then return the input
2: Remove all characters except "-", "+", "." and digits
3: Store the first character in a variable
4: Remove all "+" and "-" (if exists) after the first character
5: if the first character is "." then replace it with "0."
6. Finally remove any duplicate decimal point (".") if exists

这里有一些虚拟数据来测试格式化功能

const dummyData = [
  "",
  "+",
  "-",
  ".",
  ".123",
  "+.123",
  "123.3.23",
  "12sfdlj3lfs.s++d_f",
  "12--++.123",
];

从以上评论...

"Why does the OP not restrict the user input by a number type input field like with ... <input type="number"/>?"

"Any type="text" and custom validation based approach, if done properly, has the tendency to grow more complex since, from a UX perspective, an immediate value sanitizing (while typing or pasting) also has to take care of reestablishing the user's most recent caret position."

证明上述复杂性...

function stripNeedlessDataFromBoundFieldValue() {
  this.value = this.value.replace((/[-+.]$/), '');
}

function getSanitizedValue(value) {
  value = value
    // remove any leading and trailng whitespace (sequences).
    .trim()
    // remove any character not equal to minus, plus, dot and digit.
    .replace((/[^-+.\d]+/g), '');

  if (value.length >= 1) {

    let partials = value.split(/(^[+-]?)/);
    if (partials.length === 1) {

      partials.unshift('');
    } else {
      partials = partials.slice(1);
    }
    let [ first, last ] = partials;

    last = last.replace((/[+-]+/g), '');

    // console.log([ first, last ]);

    partials = last.split('.');
    if (partials.length === 1) {

      partials.unshift('');
    } else {
      partials = [
        partials.shift(),
        ['.', partials.join('')].join(''),
      ];
    }
    first = [first, partials[0]].join('');
    last = partials[1];

    value = [first, last]
      .join('')
      .replace(
        // trim any sequence of leading zeros into a single one.
        (/(^[+-]?)0+/),
        (match, sign) => [(sign || ''), 0].join('')
      )
      .replace(
        // always ensure a single zero before a leading sole decimal point.
        (/(^[+-]?)\.+/),
        (match, sign) => [(sign || ''), '0.'].join('')
      );
  }
  return value;
}

function sanitizeInputValue(evt) {
  const elmNode = evt.currentTarget;

  const currentValue = elmNode.value;
  const sanitizedValue = getSanitizedValue(currentValue);

  if (currentValue !== sanitizedValue) {
    const diff = sanitizedValue.length - currentValue.length;
    const { selectionStart, selectionEnd } = elmNode;

    elmNode.value = sanitizedValue;

    elmNode.selectionStart =
      (selectionStart + diff > 0) ? selectionStart + diff : selectionStart;
    elmNode.selectionEnd =
      (selectionEnd + diff > 0) ? selectionEnd + diff : selectionEnd;
  }
}

function main() {
  const textInput = document.querySelector('[type="text"]');

  const finalizeBoundFieldValueDebounced = _.debounce(
    stripNeedlessDataFromBoundFieldValue.bind(textInput), 1200
  );
  textInput.addEventListener('input', evt => {
    sanitizeInputValue(evt);
    finalizeBoundFieldValueDebounced();
  });

  // // whithout delayed trimming of trailing dot.
  //
  // document
  //   .querySelector('[type="text"]')
  //   .addEventListener('input', sanitizeInputValue);
}

main();
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>

<input type="text" placeholder="... number only ..."/>

...并将其直接与数字类型字段进行比较...

<input type="number" placeholder="native number type"/>

...以及 Micahel Hamami 的方法,特此付诸实施...

function sanitizeInputValue({ currentTarget }) {
  currentTarget.value = currentTarget.value.replace(/[^0-9,+,-,.]+/g, "");
}
function main() {
  document
    .querySelector('[type="text"]')
    .addEventListener('input', sanitizeInputValue);
}
main();
<input type="text" placeholder="... number only ..."/>