#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
.
- Поскольку вы уже обрабатываете событие, просто замените
v-model="quantity"
наv-bind:value="quantity"
- Не отправляйте событие со значением
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>