简体   繁体   English

仅接受数字的 Vue 输入

[英]Vue input that accepts only numbers

I'd like a text input to accept only a sequence of numbers.我想要一个文本输入来只接受一个数字序列。 Any other char should be ignored silently.任何其他字符都应该被忽略。 Here's a simplified version of my component:这是我的组件的简化版本:

<template>
  <div id="app">
    <input :value="tel" @input="setTel" placeholder="only numbers" />
    <p>{{ tel }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data: () => ({
    tel: "1234"
  }),

  methods: {
    setTel(v) {
      const val = v.target.value.replace(/[^0-9]/g, "");
      this.tel = val;
      /*this.tel = v.target.value = v.target.value.replace(/[^0-9]/g, "");*/
    }
  }
};
</script>

In React, there's the concept of controlled components , but I can't seem anything similar in Vue.在 React 中,有受控组件的概念,但在 Vue 中似乎没有类似的东西。

The workaround I found (which you can see in comments) is to modify the value of the input element manually, but it kind of defeats the purpose of using Vue.我找到的解决方法(你可以在评论中看到)是手动修改输入元素的值,但这有点违背了使用 Vue 的目的。

I've also tried using v-model , but the issue remains.我也尝试过使用v-model ,但问题仍然存在。

codesandbox.密码箱。

<template>
  <div id="app">
    <input v-model="tel" v-on:keyup="setTel" placeholder="only numbers" />
    <p>{{ tel }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data: () => ({
    tel: "1234"
  }),

  methods: {
    setTel(v) {
      const val = v.target.value.replace(/[^0-9]/g, "");
      this.tel = val;
      /*this.tel = v.target.value = v.target.value.replace(/[^0-9]/g, "");*/
    }
  }
};
</script>

I took a look at your sandbox and made a few modifications, Please check to see if this is what you want, the view is now updated.我查看了您的沙箱并进行了一些修改,请检查这是否是您想要的,该视图现已更新。

well you can use <input type=number... like every one said here but if you want to handle manually than what you can do is change your el.target.value in handler like好吧,您可以使用<input type=number...就像这里所说的每个人一样,但是如果您想手动处理,那么您可以做的就是在处理程序中更改 el.target.value,例如

<template>
  <div id="app">
    <input
      :value="tel"
      @input="setTel"
      placeholder="0"
    />
    <p>{{ tel }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data: () => ({
    tel: "1234"
  }),

  methods: {
    setTel(v) {
      v.target.value = v.target.value.replace(/[^0-9]/g, "");
      this.tel = v.target.value
      /*this.tel = v.target.value = v.target.value.replace(/[^0-9]/g, "");*/
    }
  }
};
</script>

and for the part where vue is showing text in your input is because when you assign same value after replacing text vue doesn't refresh the state of that particular element to avoid extra rendering对于 vue 在您的输入中显示文本的部分是因为当您在替换文本后分配相同的值时,vue 不会刷新该特定元素的状态以避免额外的渲染

Instead of handling keyup (which would allow the key to reach the input), you should handle keydown .而不是处理keyup (这将允许键到达输入),您应该处理keydown The handler should call event.preventDefault() and event.stopPropagation() to ignore the key:处理程序应调用event.preventDefault()event.stopPropagation()以忽略该键:

// ignore non-numeric keys
if (!/\d/.test(v.key)) {
  v.preventDefault()
  v.stopPropagation()
  return false
}

The input should allow meta keys through (eg to allow copy-paste or delete ):输入应该允许元键通过(例如允许复制粘贴删除):

// allow all meta keys (including Backspace) to pass through
if (v.metaKey || /(Backspace|Meta)/g.test(v.key)) {
  console.log('ignoring', v.key)
  return
}

In addition, this input should handle the input event in order to filter copy-pasted values.此外,此输入应处理input事件以过滤复制粘贴的值。

// template
<input v-model="tel" @input="onInput" v-on:keydown="setTel" />

// script
onInput(e) {
  if (e.inputType !== 'insertText' && /[^0-9]/g.test(e.target.value)) {
    const val = e.target.value.replace(/[^0-9]/g, "");
    this.tel = val;
    e.preventDefault()
    e.stopPropagation()
    return false
  }
}

demo演示

There a couple of things you can do:您可以做几件事:

  • set the input's type to number <input type=number .将输入的类型设置为 number <input type=number This will block the user from entering any character except number.这将阻止用户输入除数字以外的任何字符。 This is handled by the browser.这是由浏览器处理的。
  • you can use v-model and also add a listener @change to check the value and modify the model accordingly.您可以使用v-model并添加一个侦听@change来检查值并相应地修改模型。 Node that you can add the number modifier on the model so vue casts the input to a number `您可以在模型上添加number修饰符的节点,以便 vue 将输入转换为数字`
  • use a validation framework like vuelidate使用像vuelidate这样的验证框架

You answered your own question by setting the value on the input with the "workaround".您通过使用“解决方法”设置输入值来回答您自己的问题。 If you wanted it to work just like React Controlled Components, you could just set the target input's value to the value from the data model unless it actually changes the data model.如果您希望它像 React 受控组件一样工作,您可以将目标输入的值设置为数据模型中的值,除非它实际上更改了数据模型。 In this manner, the Vue data model would be your single source of truth.通过这种方式,Vue 数据模型将成为您的唯一真实来源。

<template>
  <div id="app">
    <input 
      v-bind:value="tel" 
      v-on:input="handleInputTel" 
      placeholder="only numbers" 
    />
    <p>{{ tel }}</p>
  </div>
</template>

<script>
export default {
  name: "App",
  data: () => ({
    tel: "1234"
  }),

  methods: {
    handleInputTel(v) {
      if (validate(v.target.value)) this.tel = v.target.value; 
      else v.target.value = this.tel;
    }
  }
};
</script>

Because the strategy of VUE to render, if the state is not different with old, this input component do not re render.因为 VUE 的渲染策略,如果 state 和 old 没有区别,这个 input 组件就不会重新渲染。 But the input DOM had changed.但是输入 DOM 发生了变化。 So, you can use $forceUpdate on input event.因此,您可以在输入事件上使用 $forceUpdate。

setTel(v) {
      const val = v.target.value.replace(/[^0-9]/g, "");
      this.tel = val;
      this.$forceUpdate();
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM