问题描述
我正在尝试使用 v-model
模式将选择包装在 Vue 自定义组件中,如 in the docs 所述。
[Vue 警告]:避免直接改变 prop,因为它的值将是 每当父组件重新渲染时被覆盖。相反,使用一个 基于道具值的数据或计算属性。道具 变异:“价值”
发现于
--->
但是,当我将 value
设为数据属性时,我失去了预期的功能。也就是说,当绑定值发生变化时,选择框不会更新。双向绑定丢失。
在不发出警告的情况下保持我期望的行为的正确方法是什么?
这是一个演示问题的交互式示例(最好在全屏模式下查看)。
Vue.component('dynamic-select-ex1',{
template: '#dynamic-select-template',props: ['value','options'],methods: {
changed() {
// custom input components need to emit the input event
this.$emit('input',event.target.value)
},},})
Vue.component('dynamic-select-ex2',props: ['options'],data() {
return {
value: null,}
},})
let example = new Vue({
el: '#example',data() {
return {
selected: null,options: [
{ text: 'Hello',value: 1 },{ text: 'World',value: 2 },{ text: 'Blah',value: 3 },{ text: 'Blerg',value: 4 },]
}
},computed: {
text() {
if (!this.selected) return
return this.options.find(({ value }) => value == this.selected).text
},methods: {
select(value) {
this.selected = value
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script type="text/x-template" id="dynamic-select-template">
<select v-model="value" @change="changed">
<option v-for="option in options" :value="option.value">{{ option.text }}</option>
</select>
</script>
<div id="example">
<label for="direct">Vue behavIoUr for native select</label><br>
<select id="direct" v-model="selected">
<option v-for="option in options" :value="option.value">{{ option.text }}</option>
</select><br>
<div>Vue behavIoUr for custom component. `value` is a prop. Warning output in console when user selects option</div>
<dynamic-select-ex1 v-model="selected" :options="options"></dynamic-select-ex1><br>
<div>Vue behavIoUr for custom component. `value` is a data property. two-way binding is broken. Selected option not updated when `value` changes.</div>
<dynamic-select-ex2 v-model="selected" :options="options"></dynamic-select-ex2><br>
<br>Selected: {{ text }}<br><br>
<button @click="select(1)">Hello</button>
<button @click="select(2)">World</button>
<button @click="select(3)">Blah</button>
<button @click="select(4)">Blerg</button><br>
</div>
解决方法
计算二传手
对于 v-model
,使用带有 v-model
的 computed setter 而不是 value
,以避免改变 prop。
您可以摆脱 change
侦听器。
<select v-model="model">
<option v-for="option in options" :value="option.value">{{ option.text }}</option>
</select>
Vue.component('dynamic-select-ex1',{
template: '#dynamic-select-template',props: ['value','options'],computed: {
model: {
get() { return this.value },set(value) { this.$emit('input',value) }
}
}
})
当计算值被访问时,它返回 prop 值,当它被设置时,它会发出。
或 :value
、@input
和 $event.target.value
另一种选择是从模板中对 value
和 $emit
进行单向绑定:
<select :value="value" @input="$emit('input',$event.target.value)">
<option v-for="option in options" :value="option.value">{{ option.text }}</option>
</select>
Vue.component('dynamic-select-ex1',})