VueJS 2 重新渲染 Table

VueJS 2 re-rendering Table

我遇到了 VueJS 渲染问题。我正在按 ajax 获取数据。在初始渲染时,table 行渲染正确,但在重新渲染更新的元素时,它没有正确渲染。

这是一张照片: Rendered Table

如您所见,第 1 行呈现正确。但是在重新渲染的第 2 行中,tds 被反转了。

这是我的代码:

var renderings = new Vue({
el: '#renderings',

data: function () {
    return {
        hasUnprocessedRenderings: false,
        renderings: {}
    };
},

methods: {
    clearData: function () {
        this.renderings = {};
    },

    updateData: function () {

        this.$http.get('http://some-url.com/renderings').then(function (response) {
            this.renderings = response.body.renderings;
            this.hasUnprocessedRenderings = response.body.hasUnprocessedRenderings;

            if (this.hasUnprocessedRenderings) {
                setTimeout(this.updateData, 10000);
            }
        });

    }
},

mounted: function() {
    this.updateData();
}

});

和我的 html:

<div id="renderings">
<table class="table table-striped table-hover table-bordered" style="margin bottom: 0;">
<thead>
<tr>
    <th>Personalisierung</th>
    <th>Format</th>
    <th>Download</th>
    <th></th>
</tr>
</thead>
<tbody>
<template v-for="rendering in renderings">
    <tr>
        <td>{{rendering.personalizationName}}</td>
        <td>{{rendering.renderTypeName}}</td>
        <template v-if="rendering.DOCUMENT_URL">
            <td><a :href="rendering.DOCUMENT_URL">{{rendering.DOCUMENT_URL}}</a></td>
            <td>
                <ul class="list-inline" style="margin-bottom: 0;">
                    <li><a :href="'http://some-url.com?pid='+rendering.PROCESS_ID" title="refresh"><i class="fa fa-refresh" aria-hidden="true"></i></a></li>
                    <li><a :href="'http://some-url.com?pid='+rendering.PROCESS_ID" title="delete"><i class="fa fa-trash-o" aria-hidden="true"></i></a></li>
                </ul>
            </td>
        </template>
        <template v-else>
            <td colspan="2" style="text-align: center;">
                <i class="fa fa-cog fa-spin fa-fw"></i>
                <span>In Bearbeitung..</span>
            </td>
        </template>
    </tr>
</template>
</tbody>
</table>
</div>

所以我的问题是:如何修复该行是否正确重新呈现?

感谢您的帮助。 :-)

编辑#1: 这是一个 jsfiddle,问题也出现在这里:https://jsfiddle.net/dt1kt06g/

似乎这种行为是 Vue 虚拟 DOM 算法优化的副作用。发生更新时,Vue 会尽量减少元素移动,而是重用和修补现有的 DOM 个节点。

当您在数据更新后检查 JSFiddle 中生成的 HTML 时,您会注意到第二个 <tr> 中的最后一个 <td> 仍然具有属性 colspan="2" style="text-align: center;",这给了我们一个提示,这个 <td> 元素被错误地从 v-else 中先前呈现的 "In Progress" 单元格中重用了。 (我不确定这是否可以被描述为 Vue 中的错误...)

无论如何,这个问题有一个解决方法:Vue 有一个特殊的 key 属性,它为节点差异算法提供了如何处理元素的提示 (see documentation)。在您的示例中,向 v-else 分支中的 <td> 添加一个密钥就足够了:

<template v-else>
    <td colspan="2" style="text-align: center;" :key="rendering.PROCESS_ID">
    ...

这是您的 JSFiddle 的 fixed version

问题可能与您使用 this.renderings = {...}

将数据分配给对象的方式有关

要分配对象属性,您应该为每个新值使用 Vue.set(this.renderings, key, value),或者 this.renderings = Object.assign({}, this.renderings, newData)

根据您使用的数据的嵌套程度,这可能完美或不完美,您可以在此处找到有关它的更多信息:https://vuejs.org/v2/guide/reactivity.html