当列表更改时,为什么v-for内部组件中的v-model(使用计算列表)会怪异地变化?

时间:2019-06-06 13:36:32

标签: javascript vue.js

我正在使用计算列表显示几种形式,用于更改数据库中的注释。 (通过axios的后端Symfony / api请求,但不相关)

注释本身的表单位于Vue组件中。 计算的列表基于一个列表,该列表在装入页面时被加载(并设置为data属性),然后由计算的属性中的输入搜索框过滤该列表。

现在,当我在输入框中键入不同的内容并且注释组件得到更新时,v模型和标签混乱了。

我已经在几种浏览器中进行了测试,并且在主要浏览器中的行为相同。

我还搜索了文档,但没有找到解决方案。

再现行为的示例:

<!DOCTYPE html>
<html>
<div id="app"></app>
</html>
const ChangeCommentForm = {
    name: 'ChangeCommentForm',
    props: ['comment', 'id'],
    data() {
        return {
            c: this.comment,
            disabled: false
        };
    },
    template: `
<form>
  <div>{{ comment }}</div>
  <input :disabled="disabled" type="text" v-model="c">
  <button type="submit" @click.prevent="changeComment">
    Change my comment
  </button>
</form>
`,
    methods: {
        changeComment() {
            this.disabled = true;
            // do the actual api request (should be unrelated)
            // await api.changeCommentOfFruit(this.id, this.c),
            // replacing this with a timeout for this example
            window.setTimeout(() => this.disabled = false, 1000);
        }
    }
};

const App = {
    components: {ChangeCommentForm},
    data() {
        return {
            fruits: [
                {id: 1, text: "apple"},
                {id: 2, text: "banana"},
                {id: 3, text: "peach"},
                {id: 4, text: "blueberry"},
                {id: 5, text: "blackberry"},
                {id: 6, text: "mango"},
                {id: 7, text: "watermelon"},
            ],
            search: ''
        }
    },
    computed: {
        fruitsFiltered() {

            if (!this.search || this.search === "")
                return this.fruits;

            const r = [];
            for (const v of this.fruits)
                if (v.text.includes(this.search))
                    r.push(v);
            return r;
        }
    },
    template: `
<div>
  <form><input type="search" v-model="search"></form>
  <div v-for="s in fruitsFiltered">
    <ChangeCommentForm :id="s.id" :comment="s.text"/>
  </div>
</div>
`
};

const vue = new Vue({
    el: '#app',
    components: {App},
    template: '<app/>'
});

只需在搜索框中输入一些字母 有关代码笔的示例:https://codepen.io/anon/pen/KLLYmq

现在如示例中所示,CommentChangeForm中的div已正确更新,但是v模型已损坏。

我想知道我是否错过了什么,或者这是Vue中的错误?

1 个答案:

答案 0 :(得分:1)

为了在渲染之间保留DOM元素的状态,重要的是v-for元素还具有key属性。渲染之间的此键应保持一致。

在这里看来,以下方法可以解决问题:

<div v-for="s in fruitsFiltered" :key="s.id">
  <ChangeCommentForm :id="s.id" :comment="s.text"/>
</div>

请参阅:

https://vuejs.org/v2/guide/list.html#Maintaining-State

https://vuejs.org/v2/api/#key