Vue mutate prop 由带有同步修饰符的 v-bind 绑定
Vue mutate prop binded by v-bind with sync modifier
我的组件数据中有一个对象。现在,我只是使用 v-bind.sync
指令将对象的所有属性作为 prop 绑定到子组件。我正在使用内置 update
事件从子组件更新这些道具,但我仍然在控制台中收到 Avoid mutation props directly
错误。这是附加的最小示例。
父组件
<template>
<div>
<oslo v-bind.sync="data" />
</div>
</template>
<script>
import Oslo from '@/components/Oslo.vue'
export default {
components: {
Oslo,
},
name: 'OsloParent',
data() {
return {
data: {
data: {
name: 'Oslo name',
access: 'admin'
}
},
}
},
}
</script>
子组件
<template>
<div>
<input type="text" v-model="name" @keyup="$emit('update:name', name)" />
<input type="text" v-model="access" @keyup="$emit('update:access', access)" />
</div>
</template>
<script>
export default {
props: {
name: String,
access: String
},
name: 'Oslo',
}
</script>
这只是我为重现问题而创建的示例组件。实际组件应该通过双向绑定处理如此多的道具,这就是我使用 v-bind
指令和 sync
修饰符绑定数据的原因。这是来自控制台的 Vue 警告(最常见)。
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "name"
有什么改进的建议或让 Vue 对此特定情况发出警告吗?上面给出的组件按预期工作,但 Vue 抛出错误。
如果您有许多属性要从子组件侦听,您可以只传递一个对象并同步它而不是单个属性。请参阅以下示例:
Vue.config.productionTip = false
Vue.config.devtools = false
Vue.component('Oslo', {
template: `
<div>
<input type="text" v-model="comp_name" @keyup="$emit('update:name', comp_name)" />
<input type="text" v-model="comp_access" @keyup="$emit('update:access', comp_access)" />
</div>
`,
props: {
data: {
name: String,
access: String,
}
},
data() {
return {
comp_name: this.data.name,
comp_access: this.data.access
}
}
})
new Vue({
el: '#app',
data() {
return {
doc: {
name: 'Oslo name',
access: 'admin'
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<span>---- {{ this.doc.name }}----</span>
<span>---- {{ this.doc.access }}----</span>
<oslo :data="this.doc" v-bind.sync="doc" />
</div>
</div>
我发现你的例子有两个问题,可能会导致这个失败。
直接使用v-model
到属性。使用 v-bind
而不是让它只显示。并使用 v-on:change
处理程序触发 $emit('update:propertyname', value)
并发送新值以在 object.
上更新
在 $emit
中发送的值似乎是空的,因此没有任何变化。请改用 $event.target.value
。
旁注:v-on:keyup
可能不是最适合收听的事件,因为输入也可以是 drag-and-dropped。那样的话听v-on:change
比较好
仅使用 v-bind.sync
而不是 v-bind:propertyName.sync
时事件侦听器的注意事项:
如果您想从 parent 上的 child 组件监听 update:propertyName
事件,您必须使用 .capture
修饰符。否则 update
事件会被 child 组件上的 v-on:update:propertyName
捕获,并且不会冒泡到 parent.
因此,您可以在 <oslo>
标签上使用 v-on:update:name.capture="someMethod"
。并且在 parent 的 methods
中有这个 someMethod
。调用后,事件将在 child 组件上触发,该组件将更新 object,从而更新 属性.
总计:
let Oslo = {
props: {
name: String,
access: String
},
name: 'Oslo',
template: `<div>
<input type="text" :value="name" @change="$emit('update:name', $event.target.value)" />
<input type="text" :value="access" @change="$emit('update:access', $event.target.value)" />
</div>`
}
new Vue({
el: "#app",
components: {
Oslo,
},
data: {
thedata: {
name: 'Oslo name',
access: 'admin'
}
},
methods: {
nameWillBeUpdated: function(v) {
console.log('New value of name will be:', v);
// After this, the `update:name` event handler of the
// child component is triggered and the value will change.
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<span>{{this.thedata.name}} - {{this.thedata.access}}</span>
<oslo
v-bind.sync="thedata"
v-on:update:name.capture="nameWillBeUpdated"
/>
</div>
我的组件数据中有一个对象。现在,我只是使用 v-bind.sync
指令将对象的所有属性作为 prop 绑定到子组件。我正在使用内置 update
事件从子组件更新这些道具,但我仍然在控制台中收到 Avoid mutation props directly
错误。这是附加的最小示例。
父组件
<template>
<div>
<oslo v-bind.sync="data" />
</div>
</template>
<script>
import Oslo from '@/components/Oslo.vue'
export default {
components: {
Oslo,
},
name: 'OsloParent',
data() {
return {
data: {
data: {
name: 'Oslo name',
access: 'admin'
}
},
}
},
}
</script>
子组件
<template>
<div>
<input type="text" v-model="name" @keyup="$emit('update:name', name)" />
<input type="text" v-model="access" @keyup="$emit('update:access', access)" />
</div>
</template>
<script>
export default {
props: {
name: String,
access: String
},
name: 'Oslo',
}
</script>
这只是我为重现问题而创建的示例组件。实际组件应该通过双向绑定处理如此多的道具,这就是我使用 v-bind
指令和 sync
修饰符绑定数据的原因。这是来自控制台的 Vue 警告(最常见)。
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "name"
有什么改进的建议或让 Vue 对此特定情况发出警告吗?上面给出的组件按预期工作,但 Vue 抛出错误。
如果您有许多属性要从子组件侦听,您可以只传递一个对象并同步它而不是单个属性。请参阅以下示例:
Vue.config.productionTip = false
Vue.config.devtools = false
Vue.component('Oslo', {
template: `
<div>
<input type="text" v-model="comp_name" @keyup="$emit('update:name', comp_name)" />
<input type="text" v-model="comp_access" @keyup="$emit('update:access', comp_access)" />
</div>
`,
props: {
data: {
name: String,
access: String,
}
},
data() {
return {
comp_name: this.data.name,
comp_access: this.data.access
}
}
})
new Vue({
el: '#app',
data() {
return {
doc: {
name: 'Oslo name',
access: 'admin'
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div>
<span>---- {{ this.doc.name }}----</span>
<span>---- {{ this.doc.access }}----</span>
<oslo :data="this.doc" v-bind.sync="doc" />
</div>
</div>
我发现你的例子有两个问题,可能会导致这个失败。
直接使用
上更新v-model
到属性。使用v-bind
而不是让它只显示。并使用v-on:change
处理程序触发$emit('update:propertyname', value)
并发送新值以在 object.在
$emit
中发送的值似乎是空的,因此没有任何变化。请改用$event.target.value
。
旁注:v-on:keyup
可能不是最适合收听的事件,因为输入也可以是 drag-and-dropped。那样的话听v-on:change
比较好
仅使用 v-bind.sync
而不是 v-bind:propertyName.sync
时事件侦听器的注意事项:
如果您想从 parent 上的 child 组件监听 update:propertyName
事件,您必须使用 .capture
修饰符。否则 update
事件会被 child 组件上的 v-on:update:propertyName
捕获,并且不会冒泡到 parent.
因此,您可以在 <oslo>
标签上使用 v-on:update:name.capture="someMethod"
。并且在 parent 的 methods
中有这个 someMethod
。调用后,事件将在 child 组件上触发,该组件将更新 object,从而更新 属性.
总计:
let Oslo = {
props: {
name: String,
access: String
},
name: 'Oslo',
template: `<div>
<input type="text" :value="name" @change="$emit('update:name', $event.target.value)" />
<input type="text" :value="access" @change="$emit('update:access', $event.target.value)" />
</div>`
}
new Vue({
el: "#app",
components: {
Oslo,
},
data: {
thedata: {
name: 'Oslo name',
access: 'admin'
}
},
methods: {
nameWillBeUpdated: function(v) {
console.log('New value of name will be:', v);
// After this, the `update:name` event handler of the
// child component is triggered and the value will change.
},
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<span>{{this.thedata.name}} - {{this.thedata.access}}</span>
<oslo
v-bind.sync="thedata"
v-on:update:name.capture="nameWillBeUpdated"
/>
</div>