为什么在使用v-for时Vue中的值无法正确更新?(Why value doesn't updated correctly in Vue when using v-for?)

我在这里创建了基本的jsfiddle。

var child = Vue.component('my-child', { template: '<div> '+ '<div>message: <input v-model="mytodoText"></div> <div>todo text: {{todoText}}</div>'+ '<button @click="remove">remove</button>' + '</div>', props:['todoText'], data: function(){ return { mytodoText: this.todoText } }, methods: { remove: function(){ this.$emit('completed', this.mytodoText); } } }); var root = Vue.component('my-component', { template: '<div><my-child v-for="(todo, index) in mytodos" v-bind:index="index" v-bind:todoText="todo" v-on:completed="completed"></my-child></div>', props:['todos'], data: function(){ return { mytodos: this.todos } }, methods: { completed: function(todo){ console.log(todo); var index = this.mytodos.indexOf(todo, 0); if (index > -1) { this.mytodos.splice(index, 1); } } } }); new Vue({ el: "#app", render: function (h) { return h(root, { props: {todos: ['text 1', 'text 2', 'text 3']} }); } });

代码很简单:根组件接收todos(字符串)数组,使用子组件迭代它们并通过props传递一些值点击顶部的“删除”按钮,你会看到结果 - 我希望有

消息:文本2待办事项文本:文本2

而是拥有:

消息: 文本1待办事项文本:文本2

根据我的理解,vue应该删除第一个元素并保留其余元素。 但实际上我有某种“混合”。

你能解释它为什么会发生以及它是如何工作的吗?

I've created basic jsfiddle here.

var child = Vue.component('my-child', { template: '<div> '+ '<div>message: <input v-model="mytodoText"></div> <div>todo text: {{todoText}}</div>'+ '<button @click="remove">remove</button>' + '</div>', props:['todoText'], data: function(){ return { mytodoText: this.todoText } }, methods: { remove: function(){ this.$emit('completed', this.mytodoText); } } }); var root = Vue.component('my-component', { template: '<div><my-child v-for="(todo, index) in mytodos" v-bind:index="index" v-bind:todoText="todo" v-on:completed="completed"></my-child></div>', props:['todos'], data: function(){ return { mytodos: this.todos } }, methods: { completed: function(todo){ console.log(todo); var index = this.mytodos.indexOf(todo, 0); if (index > -1) { this.mytodos.splice(index, 1); } } } }); new Vue({ el: "#app", render: function (h) { return h(root, { props: {todos: ['text 1', 'text 2', 'text 3']} }); } });

Code is simple: root component receives array of todos (strings), iterates them using child component and pass some values through the props Click on the top "remove" button and you will see the result - I'm expecting to have

message: text 2 todo text: text 2

but instead having:

message: text 1 todo text: text 2

From my understanding vue should remove the first element and leave the rest. But actually I have some kind of "mix".

Can you please explain why does it happen and how it works?

最满意答案

这是因为Vue试图“重用”DOM元素以最小化DOM突变。 请参阅: https : //vuejs.org/v2/guide/list.html#key

您需要为每个子组件分配一个唯一键:

v-bind:key="Math.random()"

在现实世界中,密钥将是例如从数据库中提取的ID。

This is due to the fact that Vue try to "reuse" DOM elements in order to minimize DOM mutations. See: https://vuejs.org/v2/guide/list.html#key

You need to assign a unique key to each child component:

v-bind:key="Math.random()"

where in real-world the key would be for example an ID extracted from a database.

为什么在使用v-for时Vue中的值无法正确更新?(Why value doesn't updated correctly in Vue when using v-for?)

我在这里创建了基本的jsfiddle。

var child = Vue.component('my-child', { template: '<div> '+ '<div>message: <input v-model="mytodoText"></div> <div>todo text: {{todoText}}</div>'+ '<button @click="remove">remove</button>' + '</div>', props:['todoText'], data: function(){ return { mytodoText: this.todoText } }, methods: { remove: function(){ this.$emit('completed', this.mytodoText); } } }); var root = Vue.component('my-component', { template: '<div><my-child v-for="(todo, index) in mytodos" v-bind:index="index" v-bind:todoText="todo" v-on:completed="completed"></my-child></div>', props:['todos'], data: function(){ return { mytodos: this.todos } }, methods: { completed: function(todo){ console.log(todo); var index = this.mytodos.indexOf(todo, 0); if (index > -1) { this.mytodos.splice(index, 1); } } } }); new Vue({ el: "#app", render: function (h) { return h(root, { props: {todos: ['text 1', 'text 2', 'text 3']} }); } });

代码很简单:根组件接收todos(字符串)数组,使用子组件迭代它们并通过props传递一些值点击顶部的“删除”按钮,你会看到结果 - 我希望有

消息:文本2待办事项文本:文本2

而是拥有:

消息: 文本1待办事项文本:文本2

根据我的理解,vue应该删除第一个元素并保留其余元素。 但实际上我有某种“混合”。

你能解释它为什么会发生以及它是如何工作的吗?

I've created basic jsfiddle here.

var child = Vue.component('my-child', { template: '<div> '+ '<div>message: <input v-model="mytodoText"></div> <div>todo text: {{todoText}}</div>'+ '<button @click="remove">remove</button>' + '</div>', props:['todoText'], data: function(){ return { mytodoText: this.todoText } }, methods: { remove: function(){ this.$emit('completed', this.mytodoText); } } }); var root = Vue.component('my-component', { template: '<div><my-child v-for="(todo, index) in mytodos" v-bind:index="index" v-bind:todoText="todo" v-on:completed="completed"></my-child></div>', props:['todos'], data: function(){ return { mytodos: this.todos } }, methods: { completed: function(todo){ console.log(todo); var index = this.mytodos.indexOf(todo, 0); if (index > -1) { this.mytodos.splice(index, 1); } } } }); new Vue({ el: "#app", render: function (h) { return h(root, { props: {todos: ['text 1', 'text 2', 'text 3']} }); } });

Code is simple: root component receives array of todos (strings), iterates them using child component and pass some values through the props Click on the top "remove" button and you will see the result - I'm expecting to have

message: text 2 todo text: text 2

but instead having:

message: text 1 todo text: text 2

From my understanding vue should remove the first element and leave the rest. But actually I have some kind of "mix".

Can you please explain why does it happen and how it works?

最满意答案

这是因为Vue试图“重用”DOM元素以最小化DOM突变。 请参阅: https : //vuejs.org/v2/guide/list.html#key

您需要为每个子组件分配一个唯一键:

v-bind:key="Math.random()"

在现实世界中,密钥将是例如从数据库中提取的ID。

This is due to the fact that Vue try to "reuse" DOM elements in order to minimize DOM mutations. See: https://vuejs.org/v2/guide/list.html#key

You need to assign a unique key to each child component:

v-bind:key="Math.random()"

where in real-world the key would be for example an ID extracted from a database.