Vue组件属性更改不会触发重新渲染

Rey*_*cke 6 vue-component vuejs2

在我的Vue 2应用程序中,我有一个大对象,它从根组件向下传递到几个子级作为道具。当我更改对象的某些属性时,子组件应更新并重新呈现。在某些情况下,它们会这样做,在其他情况下,它们不会。我需要一些帮助来找出为什么它不起作用。

这是一个子组件,不会更新:

<template>
<div class="upgradeBar">
    {{level}}
    <div
            v-for="lvlNum in maxLevel + 1"
            class="level"
            v-bind:class="{reached: isLevelReached(lvlNum - 1)}"
    ></div>

    <button
            class="btnUpgrade"
            @click="onLevelUp()"
            v-if="!isLevelReached(maxLevel)"
    >
        +
    </button>
</div>
</template>


<script lang="ts">
import {Component, Prop, Vue} from 'vue-property-decorator';
import Upgradable from "../../../models/Upgradable";

@Component()
export default class UpgradeBar extends Vue {
    name: 'UpgradeBar';

    @Prop() entity: Upgradable;

    get level(): number {
        return this.entity.level;
    }

    get maxLevel(): number {
        return this.entity.MAX_LEVEL;
    }

    onLevelUp() {
        this.entity.levelUp();
    }

    isLevelReached(level: number): Boolean {
        return this.entity.level >= level;
    }
}
</script>
Run Code Online (Sandbox Code Playgroud)

该组件的调用方式如下:

<UpgradeBar :entity="entity" />
Run Code Online (Sandbox Code Playgroud)

所有代码均有效。当我单击btnUpgrade按钮entity.level时,确实发生了更改,但是我需要关闭并重新打开组件才能看到更改。而且浏览器开发工具不会立即显示更改。我需要单击该组件以刷新调试器中的值。

编辑:entity该类基本上看起来像这样(节选):

class Entity {
    name: string = 'some name';
    level: number = 1;
}
Run Code Online (Sandbox Code Playgroud)

我进行了更深入的搜索,似乎可以归结为:对象的某些属性是反应性的(它们具有由vue创建的getter / setter),而有些则没有。entity.name有一个setter,因此更改它会更新组件。entity.level才不是。问题是:为什么要区别对待他们?这是一条日志:

实体的console.log

Dan*_*iel 8

如果没有看到 的代码就无法确定entity.levelUp,但这似乎是一个反应性问题,可以通过Vue.$set在该函数内部使用来解决。

您可以通过this.$forceUpdate(); 在后面添加来确认是这种情况this.entity.levelUp();

更新

this._level = this._level + 1;

可以改为

Vue.$set(this, _level, this._level + 1); 您需要在该组件/文件中导入 Vue 才能访问 $set 函数

  • 您应该删除 forceUpdate 进行测试。保留 forceUpdate 会影响性能,因为它会对所有对象进行全面检查,而不是使用反应性来选择性更新。这个 https://vuejs.org/v2/guide/reactivity.html 值得一读(在理解之前我已经阅读了多次) (3认同)

Ste*_*mas 5

您没有显示(或者我找不到)更改对象的代码,但是您是使用$set()还是Vue.set()直接更改对象的属性?由于反应性限制,直接更改属性通常不起作用


编辑添加:

我现在明白了。我想你想要这样的东西:

this.$set(this, '_level', this._level + 1);
Run Code Online (Sandbox Code Playgroud)