VueJS嵌套组件不会更新操作

时间:2017-08-02 15:51:31

标签: javascript vue.js vuejs2

This example官方指南正常(当然)。

然后我尝试将它作为一个组件,它也有效。

但是,一旦嵌套在父组件中,消息就无法撤消,我无法弄清楚原因。

Vue.component('todo-item', {
  props: ['todo'],
  template: '<div>' +
            '<li>{{ todo.text }}</li>' +
            '<button v-on:click="reverseMessage">Reverse Message</button>' +
            '</div>',
  methods: {
  reverseMessage: function () {
    var reversed = this.todo.text.split('').reverse().join('');
    console.log('tried with ' + reversed);
    this.todo.text = reversed;
  }
 }
});

这是JSFiddle:https://jsfiddle.net/37y1ukjh/

3 个答案:

答案 0 :(得分:1)

看看这个fiddle

这是因为one-way data flow。你不应该试图修改道具的价值。

  

所有道具形成了儿童财产和之间的单向向下绑定   父级:当父属性更新时,它将向下流动到   孩子,但不是相反。   这可以防止子组件意外地改变父组件   状态,这可能会使您的应用程序的数据流更难以推理。

情侣选项:
定义一个本地数据属性,该属性使用prop的初始值作为其初始值并使用该本地属性

value:
props: ['initialCounter'],
data: function () {
  return { counter: this.initialCounter }
}

定义一个计算属性,该属性根据prop的值计算并使用该计算属性

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

另一种选择是使用事件来触发父方法来更改道具,但在这种情况下似乎不需要。

答案 1 :(得分:1)

其他答案已经注意到您的代码不起作用的原因是因为您不应该改变属性。但是,小提琴中的代码不起作用的原因是因为eee传递了静态数组。换句话说,由于eee的值绑定到硬编码到属性中的对象,因此该值永远不会转换为被动对象。

如果您改为传递eee 数据属性,则该数组将被转换为被动数组,您的代码将按预期运行。< / p>

Vue.component('todo-item', {
  props: ['todo'],
  template: '<div>' +
    '<li>{{ todo.text }}</li>' +
    '<button v-on:click="reverseMessage">Reverse Message</button>' +
    '</div>',
  methods: {
    reverseMessage: function() {
      var reversed = this.todo.text.split('').reverse().join('');
      this.todo.text = reversed;
    }
  }
});

Vue.component('todo-list', {
  props: ['eee'],
  template: '<div><todo-item' +
    ' v-for="item in eee"' +
    ' v-bind:todo="item"' +
    ' v-bind:key="item.id">' +
    ' </todo-item></div>',

});

var app7 = new Vue({
  el: '#app-7',
  data: {
    todos: [{
      id: 0,
      text: 'Vegetables'
    }, {
      id: 1,
      text: 'Cheese'
    }, {
      id: 2,
      text: 'Whatever else humans are supposed to eat'
    }]
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.js"></script>
<div id="app-7">
  <ol>

    <todo-list v-bind:eee="todos"></todo-list>
  </ol>
</div>

请注意对模板的更改:

<todo-list v-bind:eee="todos"></todo-list>

和Vue:

var app7 = new Vue({
  el: '#app-7',
  data:{
    todos: [{ id: 0, text: 'Vegetables' },{ id: 1, text: 'Cheese' },{ id: 2, text: 'Whatever else humans are supposed to eat' }]
  }
})

这就是我在代码中所做的所有更改,以使其按预期工作。

这是作为属性传递的反应对象和数组在Vue中的工作方式。来自the documentation

  

请注意,JavaScript中的对象和数组是通过引用传递的,所以   如果prop是一个数组或对象,则改变对象或数组本身   孩子内部会影响父母的状态。

如果以这种方式改变对象或数组,Vue将抱怨。如果你试图将对象或数组设置为完全不同的对象或数组,那么Vue会抱怨。

该行为是否期望设计决定。有时你可能想要利用它,有时却不想利用它。

答案 2 :(得分:0)

问题是您正在尝试修改组件的道具。 道具不应修改:相反,您可以:

  1. 将其存储为数据属性,
  2. 每当单击按钮时,修改它(在这种情况下,将其反转)。
  3. 虽然这种方法可能听起来不必要地冗长,但这里的优势在于您只需使用模板中组件数据中的文本,它就会被动反应:)数据的更改将反映在DOM本身中。

    Vue.component('todo-item', {
        props: ['todo'],
        data: function() {
            // Store inherited props in data
            return {
                text: this.todo.text
            };
        },
        template: '<div>' +
                    '<li>{{ text }}</li>' +
                    '<button v-on:click="reverseMessage">Reverse Message</button>' +
                  '</div>',
        methods: {
          reverseMessage: function () {
            // Reverse text in data and overwrite it
            this.text = this.text.split('').reverse().join('');
          }
        }
      });
    

    请参阅此处的示例:https://jsfiddle.net/teddyrised/37y1ukjh/3/或下面的概念验证代码段:

      Vue.component('todo-item', {
        props: ['todo'],
        data: function() {
        	return {
          	text: this.todo.text
          };
        },
        template: '<div>' +
                    '<li>{{ text }}</li>' +
                    '<button v-on:click="reverseMessage">Reverse Message</button>' +
                  '</div>',
        methods: {
          reverseMessage: function () {
            this.text = this.text.split('').reverse().join('');
          }
        }
      });
    
      Vue.component('todo-list', {
        props: ['eee'],
        template: '<div><todo-item' +
                    ' v-for="item in eee"' +
                    ' v-bind:todo="item"' +
                    ' v-bind:key="item.id">' +
                  ' </todo-item></div>'
      });
    
      var app7 = new Vue({
        el: '#app-7'
      })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.2/vue.min.js"></script>
    <div id="app-7">
      <ol>
    
        <todo-list 
          v-bind:eee="[{ id: 0, text: 'Vegetables' },{ id: 1, text: 'Cheese' },{ id: 2, text: 'Whatever else humans are supposed to eat' }]">
            
        </todo-list>
      </ol>
    </div>