首页 > 解决方案 > 如何通过忽略每次按键上的无效字符来使文本类型的输入元素只接受一个数值(十进制、正数和负数)?

问题描述

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

例子:

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

我希望每个输入字符输入值都应保留当前有效字符串并用空字符替换无效输入字符

例子:

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

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

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

标签: javascriptregexvalidationsanitizationhtml-input

解决方案


从以上评论...

“为什么 OP 不通过像 ... 之类的数字类型输入字段来限制用户输入<input type="number"/>?”

“任何type="text"基于自定义验证的方法,如果处理得当,都有变得更加复杂的趋势,因为从用户体验的角度来看,即时值清理(在键入或粘贴时)还必须注意重新建立用户最近的插入符号位置。 "

证明上述复杂性...

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 ..."/>


推荐阅读