如何使用Vuetify创建一个数字整数输入?

wtlkbnrh  于 2023-01-14  发布在  Vue.js
关注(0)|答案(4)|浏览(310)

基于Is there specific number input component in Vuetify?,我尝试创建一个数字输入。
输入和输出值为unknown,因此可能为undefinednull,因为可能需要清除该字段,因此它不应响应0
如果可能,输入组件不应有"向上"/"向下"按钮。
如果用户传入一个标记isAcceptingFloatingPointNumbers = false,则此输入应仅接受整数值(不应输入浮点数)
生殖环节

<template>
  <v-app>
    <v-main>
      <v-text-field 
        type="number"
        label="number input" 
        :clearable="true"
        :model-value="num"
        @update:modelValue="num = $event"
      />
    </v-main>
  </v-app>
</template>

<script setup lang="ts">
import { ref, watch, Ref } from 'vue'

const num: Ref<unknown> = ref(undefined)

watch(num, () => console.log(num.value))
</script>

如果标志isAcceptingFloatingPointNumbers返回false,我如何确保用户只能键入整数值?我想到的唯一方法是附加一个自定义规则,如

v => Number.isInteger(v) || 'Must be integer'

但是AFAIK即使值可以是undefined,此规则也会触发。是否有办法阻止用户输入?
基于yoduh's answer我尝试了这个(复制链接)
NumberField.vue

<template>
  <v-text-field 
    type="number"
    label="number input" 
    :clearable="true"
    :model-value="num"
    @update:modelValue="emit('update:modelValue', $event)"
    @keypress="filterInput"
  />
</template>

<script setup lang="ts">
const props = defineProps<{
  num: unknown;
  isAcceptingFloatingPointNumbers: boolean;
}>();

const emit = defineEmits<{
  (e: "update:modelValue", newValue: unknown): void;
}>();

function filterInput(inputEvent) {
  if(props.isAcceptingFloatingPointNumbers.value) {
    return true;
  }
  
  const inputAsString = inputEvent.target.value.toString() + inputEvent.key.toString();
  const inputValue = Number(inputAsString);
  
  if(!Number.isInteger(inputValue)) {
    inputEvent.preventDefault();
  }
  
  return true;
}
</script>

我像这样消耗组件

<template>
  <number-field :num="num" :isAcceptingFloatingPointNumbers="false" @update:model-value="num = $event" />
</template>

<script setup lang="ts">
import { ref, watch } from 'vue'
import NumberField from "./NumberField.vue";

const num: Ref<unknown> = ref(undefined);
  
watch(num, () => console.log(num.value));
</script>

问题是我的过滤函数出错了,仍然可以输入"12.4",因为过滤器忽略了"12.",然后将"12.4"转换为124。
有人知道怎么解决吗?

l7mqbcuq

l7mqbcuq1#

由于整数只由数字组成,因此您可以只测试每个按下的键是否为数字,而无需检查整个输入值。

function filterInput(inputEvent) {
  
  if(props.isAcceptingFloatingPointNumbers.value) {
    return true;
  }

  if(!inputEvent.target.value.length && inputEvent.key === '-'){
    return true;
  }
  
  if(!Number.isInteger(Number(inputEvent.key))) {
    // Of course, you can choose any other method to check if the key 
    // pressed was a number key, for ex. check if the event.keyCode is 
    // in range 48-57.
    inputEvent.preventDefault();
  }
  
  return true;
}

关于箭头,它不是Vuetify特定的元素,而是浏览器添加到类型编号输入的元素。您可以禁用它们like this

bis0qfac

bis0qfac2#

据我所知,您有以下要求**:**

  • 防止用户根据isAcceptingFloatingPointNumbers标志值输入(如果标志为false,则仅接受整数,否则字段应接受浮点数)。
  • 输入字段中没有向上/向下箭头。
  • 输入字段应接受0值。

如果我上面的理解是正确的,你可以简单地通过正常的文本字段和每个keyup事件实现这个要求,你可以用一个空字符串替换输入值,如果它不匹配传递有效的regEx.
现场演示**:**

const { ref } = Vue;
const { createVuetify } = Vuetify;
const vuetify = createVuetify();

let options = {
    setup: function () {
    let num = ref('');
    let isAcceptingFloatingPointNumbers = ref(false);
    
    const validateInput = () => {
      const numbersRegEx = !isAcceptingFloatingPointNumbers.value ? /[^-\d]/g : /[^-\d.]/g;
      num.value = num.value.replace(numbersRegEx, '');
    }

    return {
      num,
      validateInput
    };
  }
};

let app = Vue
.createApp(options)
.use(vuetify)
.mount('#app');
<script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
<script src="https://unpkg.com/@vuetify/nightly@3.1.1/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@vuetify/nightly@3.1.1/dist/vuetify.css"/>

<div id="app">
  <v-text-field label="Numper Input" v-model="num" v-on:keyup="validateInput"></v-text-field>
</div>
yiytaume

yiytaume3#

我认为最好的方法是创建一个自定义的过滤器函数,在按键时运行。使用你自己的自定义过滤器,你也可以删除type="number",因为它不再是必要的,并将删除输入上的向上/向下箭头。

<v-text-field 
        label="number input" 
        :clearable="true"
        :model-value="num"
        @update:modelValue="num = $event"
        @keypress="filter(event)"
      />
const filter = (e) => {
  e = (e) ? e : window.event;
  const input = e.target.value.toString() + e.key.toString();

  if (!/^[0-9]*$/.test(input)) {
    e.preventDefault();
  } else {
    return true;
  }
}

更新沙箱

djp7away

djp7away4#

根据您对@yoduh答案的评论,如果您想坚持使用type="number"(有利于减少验证非数字字符的步骤),则使用以下CSS隐藏箭头-

/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Firefox */
input[type=number] {
  -moz-appearance: textfield;
}

逻辑1-

    • keyup事件中,检查isAcceptingFloatingPointNumbers是否为false且键入的输入是否为整数,清空输入字段的值。**要检查输入值是否为整数-

1.您可以使用正则表达式模式/^-?[0-9]+$/.test(num)
1.您可以使用JS方法Number.isInteger(num)
但是,在第二种方法中,输入值的类型总是string(why?),要解决这个问题,请使用内置的Vue.js指令v-model.number将输入值的类型重新转换为数字。
演示-
x一个一个一个一个x一个一个二个一个x一个一个三个一个
这里唯一的问题是,如果用户键入123.并停止键入,那么dot将可见,因为type="number",但如果您使用此值,它将始终被解码为123
如果要限制dot的类型,请检测keypress事件上的键并阻止进一步执行。

编辑-------------

逻辑2

如果用户尝试输入浮点数,则可以使用Math.trunc(num)方法删除小数位,返回该浮点数的整数部分。
演示-

const { ref } = Vue;
const { createVuetify } = Vuetify;
const vuetify = createVuetify();

let options = {
  setup: function() {
    let num = ref(null);
    let error = ref('');
    let isAcceptingFloatingPointNumbers = ref(false);
    const validateInput = () => {
      if (!isAcceptingFloatingPointNumbers.value && !Number.isInteger(num.value)) {
        error.value = "Only integer is allowed.";
        // Keep only integer part.
        num.value = Math.trunc(num.value);
      } else {
        error.value = ''
      }

    };
    return {
      num,
      error,
      validateInput,
    };
  },
};

let app = Vue.createApp(options)
  .use(vuetify)
  .mount("#app");
.error {
  color: red;
}
<script src="https://unpkg.com/vue@next/dist/vue.global.js"></script>
<script src="https://unpkg.com/@vuetify/nightly@3.1.1/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/@vuetify/nightly@3.1.1/dist/vuetify.css"/>
<div id="app">
  <v-text-field 
    type="number"
    label="number input" 
    :clearable="true"
    v-model.number="num"
    @keyup="validateInput"
    >
  </v-text-field>
  <label class="error">{{ error }}</label>
</div>

相关问题