Как создать числовой компонент ввода в Vue с ограничениями, которые не позволяют вводить внешние ограничения - PullRequest
0 голосов
/ 27 сентября 2018

Я пытаюсь создать компонент числового ввода в Vue с минимальными и максимальными значениями, которые не позволяют печатать вне пределов без успеха:

<template id="custom-input">
  <div>
    <input :value="value" type="number" @input="onInput">
  </div>
</template>

<div id="app">
  <div>
    <span>Value: {{ value }}</span>
    <custom-input v-model="value" :max-value="50"/>
  </div>
</div>
Vue.component('custom-input', {
  template: '#custom-input',
  props: {
    value: Number,
    maxValue: Number
  },
  methods: {
    onInput(event) {
      const newValue = parseInt(event.target.value)
      const clampedValue = Math.min(newValue, this.maxValue)
      this.$emit('input', clampedValue)
    }
  }
})

new Vue({
  el: "#app",
  data: {
    value: 5
  }
})

Скрипка здесь: https://jsfiddle.net/8dzhy5bk/6/

В предыдущем примере максимальное значение установлено в 50. Если я наберу 60, оно автоматически преобразуется в 50 во вводе, но если я наберу третью цифру, это позволит продолжить ввод.Значение, передаваемое родительскому элементу, ограничено, но мне также нужно ограничить ввод, чтобы больше вводить цифры нельзя.

1 Ответ

0 голосов
/ 27 сентября 2018

Когда значение ввода больше 10, оно всегда будет испускать 10 для родительского компонента, но значение не изменяет (всегда = 10), поэтому не будет запускать реактивность ,

Одно решение , всегда сначала выдается фактическое значение (= parseInt(event.target.value)), а затем выдается максимальное значение (= Math.min(newValue, this.maxValue)) в vm.$nextTick()

Другим решением является использование this.$forceUpdate().

Обновлено : Как отметил @Husam Ibrahim, атрибут max будет работать также как <input :value="value" type="number" @input="onInput" @keydown :max="maxValue">

Ниже демо для $nextTick.

Vue.component('custom-input', {
  template: '#custom-input',
  props: {
    value: Number,
    maxValue: Number
  },
  methods: {
    onInput(event) {
      const newValue = parseInt(event.target.value)
      const clampedValue = Math.min(newValue, this.maxValue)
      this.$emit('input', newValue)
      this.$nextTick(()=>{
      	this.$emit('input', clampedValue)
      })
    }
  }
})

new Vue({
  el: "#app",
  data: {
    value: 5
  },
  methods: {
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>

<template id="custom-input">
  <div>
    <input 
      :value="value" 
      type="number" 
      @input="onInput" 
     >
  </div>
</template>

<div id="app">
  <div>
    <span>Value: {{ value }}</span>
    <custom-input v-model="value" :max-value="10"/>
  </div>
</div>

Ниже демо для vm.$forceUpdate.

Vue.component('custom-input', {
  template: '#custom-input',
  props: {
    value: Number,
    maxValue: Number
  },
  methods: {
    onInput(event) {
      const newValue = parseInt(event.target.value)
      const clampedValue = Math.min(newValue, this.maxValue)
      this.$emit('input', clampedValue)
      this.$forceUpdate()
    }
  }
})

new Vue({
  el: "#app",
  data: {
    value: 5
  },
  methods: {
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>

<template id="custom-input">
  <div>
    <input 
      :value="value" 
      type="number" 
      @input="onInput" 
     >
  </div>
</template>

<div id="app">
  <div>
    <span>Value: {{ value }}</span>
    <custom-input v-model="value" :max-value="10"/>
  </div>
</div>

Ниже демо использовать атрибут max.

Vue.component('custom-input', {
  template: '#custom-input',
  props: {
    value: Number,
    maxValue: Number
  },
  methods: {
    onInput(event) {
      const newValue = parseInt(event.target.value)
      const clampedValue = Math.min(newValue, this.maxValue)
      this.$emit('input', clampedValue)
    }
  }
})

new Vue({
  el: "#app",
  data: {
    value: 5
  },
  methods: {
  }
})
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
}

#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>

<template id="custom-input">
  <div>
    <input 
      :value="value" 
      type="number" 
      @input="onInput" 
      :max="maxValue"
     >
  </div>
</template>

<div id="app">
  <div>
    <span>Value: {{ value }}</span>
    <custom-input v-model="value" :max-value="10"/>
  </div>
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...