Vue 3 未检测到对在 Vue 组件之外创建的对象所做的更改 [英] Changes made to an object created outside of Vue component are not detected by Vue 3

查看:16
本文介绍了Vue 3 未检测到对在 Vue 组件之外创建的对象所做的更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类字符:Character.ts

    /// This is called when server responds
    public setAttributeByType(type: StatsTypes, value: number): void {
        switch (type) {
            case StatsTypes.STRENGTH:
            case StatsTypes.DEXTERITY:
            case StatsTypes.VITALITY:
            case StatsTypes.INTELIGENCE:
                this.stats[type] = value;
                break;
            default: break;
        }
    }
    ....

类实例是在我的网络代码"中的 Vue 组件之外创建的:

The class instance is created outside of Vue component in my "networking code":

    public static onStartGame(data:any):void {
        Player.character = new Character(data.data);
        Game.displayGamePage(PagesIndex.GAME_PAGE);
        requestAnimationFrame(Game.loop);
    }

并用于主要组件:Game.vue

import { defineComponent } from 'vue'
import Player from '@/Player/player';
import SceneManager, { Scenes } from '@/Render/scene_manager';
import Scene from '@/Render/scene';
import MainScene from "@/Render/scenes/main";
import MapScene from "@/Render/scenes/map";
import Game from '@/game/game';

// Components
import VplayerBar from "@/vue/subs/playerBar.vue"
import Vcharacter from "@/vue/subs/character.vue"

export enum GamePages {
    MAIN_PAGE = 1,
    MAP_PAGE,
}

export default defineComponent({
    name: "game",
    components: {
        VplayerBar,
        Vcharacter,
    },
    data() {
        return {
            page: GamePages.MAIN_PAGE,
            scenes: Scenes,
            gamePages: GamePages,
            player: Player,
            character: Player.character, /* <------------ Reference to class */
            pages: {
                character: false,
            }
        }
    },
})

...将其作为道具传递给 character.vue 组件

...which pass it down as a prop to character.vue component

export default defineComponent({
    name: "character",
    props: {
        character: {  // <---- This prop does not change
            type: Character,
            required: true
        },
        toggleCharacter: {
            type: Function, 
            required: true
        }
    },
    components: {
        VBackpack,
        VInventory
    },
    data() {
        return {
            StatsTypes,
        }
    },
    methods: {
        toglePage() {
            this.toggleCharacter()
        },
        getPortrait(isMobile:boolean = false) {
            return Character.getCharacterPortrait(this.character.faction, this.character.gender, isMobile);
        },
        addPoint(attribute:StatsTypes, value: number) {
            if (GKeyHandler.keys[Keys.SHIFT_LEFT])
                value = 10;

            CharacterHandler.addAttributePoint(Player.character, attribute, value);
            //this.character.stats[StatsTypes.STRENGTH] += 1; 
        }
    }
});

问题是,每当我在 vue 组件之外(在我的网络代码中)更改字符类实例中的任何内容时 - 例如 character.setAttributeByType(attribute, value),Vue 都看不到更改.如果我直接在 character.vue 组件中执行此操作,它会起作用(请参阅 addPoint 中的注释代码)

Problem is that whenever I change anything in character class instance outside the vue component (in my networking code) - for example character.setAttributeByType(attribute, value), Vue does not see the change. If I do this directly inside character.vue component, it works (see commented code in addPoint)

我尝试使用 Proxy &观看并没有帮助.

I tried to use Proxy & Watch and it did not help.

推荐答案

你的问题是身份"在此处

Vue 3 使用 ES6 代理使对象具有响应性.如果你做 const data = reactor(payload)datapayload 是不同的对象(不像在 Vue 2 中对象刚刚被修改带有反应式 setter/getter).

Vue 3 is using ES6 proxies to make objects reactive. If you do const data = reactive(payload), the data is different object then payload (unlike in Vue 2 where the object was just modified with reactive setters/getters).

同样适用于 Options API(您正在使用).如果你在 data() 中做 character: Player.character 结果是 this.character(在 Vue 组件中)是不同的对象然后 玩家角色.您可以通过执行 console.log(this.character === Player.character) ...例如在 mounted() 中轻松测试它 - 结果将是

Same applies for Options API (you are using). If you do character: Player.character in data() the result is this.character (inside Vue component) is different object then Player.character. You can easily test it by doing console.log(this.character === Player.character) ...for example in mounted() - result will be false

因此,如果您使用 this.character(Vue 反应式代理)进行任何更改,Vue 将检测更改并重新渲染(并将更改传播到原始对象),但如果您更改原始对象 Player.character Vue 未检测到更改...

As a result if you make any change using this.character (Vue reactive proxy), Vue will detect the change and rerender (and propagate the change to the original object) but if you change the original object Player.character the change is not detected by Vue...

简单的解决方法是使用 Vue 的 Composition API 允许您在 Vue 组件之外使用 Vue 反应性.

Simple fix is to use Vue's Composition API which allows you to use Vue reactivity outside the Vue components.

import { reactive } from `vue`

Player.character = reactive(new Character(data.data));

现在当你在 Vue 组件中使用 Player.character 初始化 data() 时,Vue 看到它已经是一个响应式代理,不再将它包装在代理中

Now when you use Player.character to initialize data() in Vue component, Vue sees it is a reactive proxy already and do not wrap it in proxy again

这篇关于Vue 3 未检测到对在 Vue 组件之外创建的对象所做的更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆