我开始了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的新手,所以我完全不知道如何修复它。有人知道如何(请解释为什么)解决这个问题吗?


当前回答

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只是警告您:您更改了组件中的道具,但当父组件重新呈现时,“list”将被覆盖,您将丢失所有更改。所以这样做是危险的。

使用computed属性,如下所示:

Vue.component('task', {
    template: '#task-template',
    props: ['list'],
    computed: {
        listJson: function(){
            return JSON.parse(this.list);
        }
    }
});

这与这样一个事实有关:在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:因为我觉得有一些关于道具和反应性的困惑,我建议你看看这个帖子

Vue.js的道具不能被改变,因为这被认为是Vue中的反模式。

您需要采取的方法是在组件上创建一个引用list的原始prop属性的data属性

props: ['list'],
data: () {
  return {
    parsedList: JSON.parse(this.list)
  }
}

现在传递给组件的列表结构通过组件的data属性被引用和改变:-)

如果您希望做的不仅仅是解析列表属性,那么请使用Vue组件的computed属性。 这允许你对你的道具做出更深入的变化。

props: ['list'],
computed: {
  filteredJSONList: () => {
    let parsedList = JSON.parse(this.list)
    let filteredList = parsedList.filter(listItem => listItem.active)
    console.log(filteredList)
    return filteredList
  }
}

上面的示例将解析您的列表道具,并将其过滤为仅活跃的list-tems,将其记录为schnitts和giggles并返回它。

注意:数据和计算属性在模板中引用相同

<pre>{{parsedList}}</pre>

<pre>{{filteredJSONList}}</pre>

很容易认为计算属性(作为一个方法)需要被调用…它不

根据VueJs 2.0,您不应该改变组件内部的道具。它们只会被父母变异。因此,您应该在数据中定义不同名称的变量,并通过观察实际的道具来更新它们。 如果列表道具被父元素更改,您可以解析它并将其分配给mutableList。这里有一个完整的解决方案。

Vue.component('task', {
    template: ´<ul>
                  <li v-for="item in mutableList">
                      {{item.name}}
                  </li>
              </ul>´,
    props: ['list'],
    data: function () {
        return {
            mutableList = JSON.parse(this.list);
        }
    },
    watch:{
        list: function(){
            this.mutableList = JSON.parse(this.list);
        }
    }
});

它使用mutableelist来呈现模板,这样就可以在组件中保证列表道具的安全。

再加上最好的答案,

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。如果未定义,则解析错误。