Компонент Vue для увеличения, уменьшения или ввода числа во ввод

#vue.js #vue-component

#vue.js #vue-компонент

Вопрос:

Я новичок в VueJS, и мне это нравится, но иногда это становится немного сложнее, если я использую компоненты. У меня есть корзина для покупок, и я хотел бы использовать увеличение / уменьшение, или пользователь может ввести определенное количество элементов в поле ввода.

Проблема в том, что Vue продолжает жаловаться, что дочерний элемент не может изменять родительские данные. Я устал от разных способов, но он не работает

Это мой компонент

 Vue.component('product-counter', {
props: ['quantity'],
data: function () {
    return {
        count: this.quantity
    }
},
template: `<div class="row">
            <div class="col-3">
                <button v-on:click="$emit('increment-quantity'); " class="btn btn-success" > <i class="fas fa-plus-circle"></i></button>
            </div>
            <div class="col-6">
                <input v-model="quantity" v-on:input="$emit('input', quantity)" class="form-control" >
            </div>

            <div class="col-3">
                <button v-on:click="$emit('decrement-quantity');" v-bind:disabled="quantity<1" class="btn btn-danger"><i class="fas fa-minus-circle"></i></button>
            </div>
          </div>
        `
})
  

Это мой компонент вызовов HTML-кода

  <product-counter v-bind:quantity="item.quan" v-on:input="item.quan=$event" v-on:increment-quantity="item.quan  " v-on:decrement-quantity="item.quan--" ></product-counter>
  

Увеличение и уменьшение работают отлично, но если вы вводите число во ввод, я получаю эту ошибку:

vue.js:634 [Предупреждение Vue]: избегайте прямого изменения prop, поскольку значение будет перезаписываться всякий раз, когда родительский компонент повторно отображает. Вместо этого используйте данные или вычисляемое свойство на основе значения prop. Изменяется реквизит: «количество»

Ответ №1:

Вы не можете привязаться к реквизиту с помощью v-model . Один из вариантов — следить за quantity реквизитом и привязывать к count нему:

 Vue.component('product-counter', {
  props: ['quantity'],
  data: function() {
    return {
      count: this.quantity
    }
  },
  watch: {
    quantity(val) {
      this.count = val;
    }
  },
  template: `<div class="row">
            <div class="col-3">
                <button v-on:click="$emit('increment-quantity'); " class="btn btn-success" > <i class="fa fa-plus-circle"></i></button>
            </div>
            <div class="col-6">
                <input v-model="count" v-on:input="$emit('input', count)" class="form-control" >
            </div>

            <div class="col-3">
                <button v-on:click="$emit('decrement-quantity');" v-bind:disabled="quantity<1" class="btn btn-danger"><i class="fa fa-minus-circle"></i></button>
            </div>
          </div>
        `
})

new Vue({
  el: '#app',
  data: {
    item: {
      quan: 0
    }
  }
});

Vue.config.productionTip = false;
Vue.config.devtools = false;  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div id="app">
  <product-counter v-bind:quantity="item.quan" v-on:input="item.quan=$event" v-on:increment-quantity="item.quan  " v-on:decrement-quantity="item.quan--"></product-counter>
</div>  

Ответ №2:

Не используйте v-model on prop. Используйте комбинацию :value= и @input .

  1. Поскольку вы уже обрабатываете событие, просто замените v-model="quantity" на v-bind:value="quantity"
  2. Не отправляйте событие со значением quantity prop, а отправляйте новое значение по input элементу. Вместо v-on:input="$emit('input', quantity)" использования v-on:input="$emit('input', $event.target.value)"

Почему

v-model="quantity" синтаксический сахар для v-bind:value="quantity" v-on:input="quantity = $event.target.value" )

Такой обработчик является проблемой, если используется в prop, потому что props — это только один способ — только родитель, который «владеет» значением, должен его изменить. Итак, мы заменяем v-on:input="quantity = $event.target.value" на v-on:input="$emit('input', $event.target.value"

v-on:input="$emit('input', quantity)" будет отправлять не новое измененное значение, а «старое» значение…

Еще лучше

…использовать computed . Код:

 Vue.component('product-counter', {
  props: ['value'],
  computed: {
    count: {
      get() { return this.value },
      set(newValue) { this.$emit('input', newValue) }
    }
  },
  template: `<div class="row">
            <div class="col-3">
                <button v-on:click="count  " class="btn btn-success" > <i class="fa fa-plus-circle"></i></button>
            </div>
            <div class="col-6">
                <input v-model.number="count" class="form-control" >
            </div>
            <div class="col-3">
                <button v-on:click="count--" v-bind:disabled="count<1" class="btn btn-danger"><i class="fa fa-minus-circle"></i></button>
            </div>
          </div>
        `
})

new Vue({
  el: '#app',
  data: {
    item: {
      quan: 0
    }
  }
});

Vue.config.productionTip = false;
Vue.config.devtools = false;  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<div id="app">
  <product-counter v-model="item.quan"></product-counter>
  <div> {{ item.quan }}</div>
</div>