【问题标题】:Vue controlled inputsVue 控制的输入
【发布时间】:2019-03-16 10:46:01
【问题描述】:

我希望文本输入只接受一个数字序列。任何其他字符都应该被忽略。这是我的组件的简化版本:

<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>

在 React 中,有 controlled components 的概念,但在 Vue 中似乎没有类似的东西。

我找到的解决方法(您可以在 cmets 中看到)是手动修改输入元素的值,但这有点违背了使用 Vue 的目的。

我也尝试过使用v-model,但问题仍然存在。

codesandbox.

【问题讨论】:

  • 尝试使用&lt;input type='number' ...
  • 你实际上可以用普通的 JS 来实现这一点,function formatNumber(element) { element.value = Number(element.value.replace(/[^0-9]/g, '')).toLocaleString(undefined, { maximumFractionDigits: 2 }); } 也可以尝试使用 keyUp 事件。
  • @BoussadjraBrahim 需要使用type='text,这种情况比^[0-9]*$更通用
  • @UgoOkoro 这就像我找到的解决方法,但是直接修改输入元素感觉不对。检查示例中的this.tel,您可以看到它得到了正确的值,只是视图没有更新......

标签: javascript vue.js vuejs2


【解决方案1】:
<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>

我查看了您的沙箱并进行了一些修改,请检查这是否是您想要的,该视图现已更新。

【讨论】:

  • 感谢您的努力,但在您的解决方案中,字母确实传递到输入,这不是最佳的。
  • 有时,似乎有必要使用this.$forceUpdate() 来让 vue 覆盖用户刚刚输入的内容。显然,vue 需要重新渲染以防止用户在输入字段中输入内容。
【解决方案2】:

你可以像这里所说的每个人一样使用&lt;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>

vue 在输入中显示文本的部分是因为当您在替换文本后分配相同的值时,vue 不会刷新该特定元素的状态以避免额外渲染

【讨论】:

  • 您发布了我在 OP 中提到的解决方法作为答案:)。我不希望将值分配给v.target.value,在这里输入数字不是重点,这可以推广到任何类型的规则。
【解决方案3】:

您应该处理keydown,而不是处理keyup(这将允许键到达输入)。处理程序应调用 event.preventDefault()event.stopPropagation() 以忽略密钥:

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

输入应该允许元键通过(例如允许复制粘贴删除):

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

此外,此输入应处理 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

【讨论】:

    【解决方案4】:

    你可以做几件事:

    • 将输入的类型设置为数字&lt;input type=number。这将阻止用户输入除数字以外的任何字符。这由浏览器处理。
    • 您可以使用v-model 并添加一个侦听器@change 来检查值并相应地修改模型。您可以在模型上添加 number 修饰符的节点,以便 vue 将输入转换为数字`
    • 使用像vuelidate这样的验证框架

    【讨论】:

      【解决方案5】:

      您通过使用“解决方法”设置输入值来回答您自己的问题。 如果您希望它像 React 受控组件一样工作,您可以将目标输入的值设置为数据模型中的值,除非它实际上更改了数据模型。通过这种方式,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>
      

      【讨论】:

        【解决方案6】:

        因为VUE的渲染策略,如果状态和old没有区别,这个输入组件就不会重新渲染。但是输入 DOM 发生了变化。 因此,您可以在输入事件上使用 $forceUpdate。

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-10-07
          • 2021-05-10
          • 2016-09-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多