我开始了https://laracasts.com/series/learning-vue-step-by-step系列。我在Vue、Laravel和AJAX的课程上停了下来,出现了这个错误:
Vue .js:2574 [Vue警告]:避免直接改变道具,因为每当父组件重新呈现时,该值将被覆盖。相反,应该使用基于道具值的数据或计算属性。道具被突变:"list"(在组件中找到)
我在main.js中有这段代码
Vue.component('task', {
template: '#task-template',
props: ['list'],
created() {
this.list = JSON.parse(this.list);
}
});
new Vue({
el: '.container'
})
我知道,当我覆盖列表道具时,问题是在created(),但我是Vue的新手,所以我完全不知道如何修复它。有人知道如何(请解释为什么)解决这个问题吗?
下面是一个小吃店组件,当我把小吃店变量直接输入v-model,就像这样,如果将工作,但在控制台中,它会给出一个错误
避免直接改变道具,因为每当父组件重新呈现时,该值将被覆盖。相反,应该使用基于道具值的数据或计算属性。
<template>
<v-snackbar v-model="snackbar">
{{ text }}
</v-snackbar>
</template>
<script>
export default {
name: "loader",
props: {
snackbar: {type: Boolean, required: true},
text: {type: String, required: false, default: ""},
},
}
</script>
消除这种变异错误的正确方法是使用监测器
<template>
<v-snackbar v-model="snackbarData">
{{ text }}
</v-snackbar>
</template>
<script>
/* eslint-disable */
export default {
name: "loader",
data: () => ({
snackbarData:false,
}),
props: {
snackbar: {type: Boolean, required: true},
text: {type: String, required: false, default: ""},
},
watch: {
snackbar: function(newVal, oldVal) {
this.snackbarData=!this.snackbarDatanewVal;
}
}
}
</script>
在加载小吃店的主组件中,你可以执行这段代码
<loader :snackbar="snackbarFlag" :text="snackText"></loader>
这对我很有用
单向数据流,
根据https://v2.vuejs.org/v2/guide/components.html,该组件遵循单向
数据流,
所有的道具在子属性和父属性之间形成了一个单向的向下绑定,当父属性更新时,它将向下流到子属性,而不是相反,这可以防止子组件意外地改变父属性,这可能会使你的应用程序的数据流更难理解。
此外,每次父组件更新所有的道具
子组件中的值将被刷新为最新值。这意味着您不应该试图改变子组件中的道具。如果你这样做了,vue会在
控制台。
通常有两种情况很容易对道具进行变异:
prop用于传入一个初始值;子组件希望随后将其用作本地数据属性。
道具作为需要转换的原始值传递进来。
这些用例的正确答案是:
定义一个本地数据属性,使用prop的初始值作为其初始值:
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
定义一个计算属性,从prop的值计算:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
这与这样一个事实有关:在Vue 2中,局部变异道具被认为是一种反模式
你现在应该做的是,如果你想在本地改变一个道具,在你的数据中声明一个字段,使用props值作为它的初始值,然后改变副本:
Vue.component('task', {
template: '#task-template',
props: ['list'],
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
你可以在Vue.js官方指南上阅读更多相关内容
注1:请注意,您的道具和数据不应使用相同的名称,即:
data: function () { return { list: JSON.parse(this.list) } } // WRONG!!
注2:因为我觉得有一些关于道具和反应性的困惑,我建议你看看这个帖子
Vue3有一个很好的解决方案。花了好几个小时才到那里。但是效果很好。
在父模板上
<user-name
v-model:first-name="firstName"
v-model:last-name="lastName"
></user-name>
子组件
app.component('user-name', {
props: {
firstName: String,
lastName: String
},
template: `
<input
type="text"
:value="firstName"
@input="$emit('update:firstName',
$event.target.value)">
<input
type="text"
:value="lastName"
@input="$emit('update:lastName',
$event.target.value)">
`
})
这是唯一能双向结合的解。我喜欢前两个答案,以良好的方式使用同步和发射更新事件,并计算属性getter setter,但这是一个工作要做的,我不喜欢这么努力工作。
再加上最好的答案,
Vue.component('task', {
template: '#task-template',
props: ['list'],
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
通过数组设置道具是为了开发/原型,在生产中确保设置道具类型(https://v2.vuejs.org/v2/guide/components-props.html),并设置一个默认值,以防道具没有被父元素填充。
Vue.component('task', {
template: '#task-template',
props: {
list: {
type: String,
default() {
return '{}'
}
}
},
data: function () {
return {
mutableList: JSON.parse(this.list);
}
}
});
这样你至少可以在mutableList中得到一个空对象,而不是JSON。如果未定义,则解析错误。