Данные Vue недоступны до вызова JSON.stringify().
Я не уверен, как решить эту проблему, потому что в ней есть много общего, и такое поведение я никогда не видел ни в JavaScript, ни в Vue.js. Конечно, я постараюсь сделать код минимальным для большинства критические и кусочки
Я использую vue-class-component(6.3.2), поэтому мои компоненты Vue(2.5.17) выглядят как классы:) Этот конкретный компонент выглядит так:
import GameInterface from '@/GameInterface';
class GameComponent extends Vue {
public gameInterface = GameInterface();
public mounted() {
this.gameInterface.launch();
}
}
GameInterface возвращает объект с методом запуска и другими игровыми переменными.
В файле интерфейса игры метод выглядит примерно так:
const GameInterface = function () {
const obj = {
gameState: {
players: {},
},
gameInitialized: false,
launch() => {
game = createMyGame(obj); // set gameInitialized to true
},
};
return obj;
}
export default GameInterface;
Отлично, это работает, объект передается в мою игру Phaser:), и он также возвращается методом, что означает, что теперь Vue может использовать этот объект.
В какой-то момент у меня есть метод получения в моем классе Vue, который выглядит так:
get currentPlayer() {
if (!this.gameInterface.gameInitialized) return null;
if (!this.gameInterface.gameState.players[this.user.id]) {
return null;
}
return this.gameInterface.gameState.players[this.user.id];
}
И, конечно же, возвращается ноль, даже если игрок и идентификатор явно присутствуют. Когда я console.log this.user.id
я получил 4
, а также gameInterface.gameState.players
возвращает объект с геттерами для игроков следующим образом:
{
4: { ... },
5: { ... },
}
Хорошо, поэтому он не возвращает игрока, даже если объект и ключ передаются правильно...
Но я нашел очень странный способ "исправить" эту проблему: добавив JSON.parse(JSON.stringify(gameState))
вот так
get currentPlayer() {
// ...
if (!this.gameInterface.gameState.players[this.user.id]) {
// add this line
JSON.stringify(this.gameInterface.gameState);
return null;
}
return this.gameInterface.gameState.players[this.user.id];
}
Он успешно возвращает текущего игрока для нас... Странно нет?
Я предполагаю, что когда мы делаем это, мы "ударяем" объект, Vue замечает некоторые изменения из-за этого и корректно обновляет объект. Кто-нибудь знает, что мне здесь не хватает?
1 ответ
Поработав над проблемой с другом, я обнаружил, что основной проблемой является специфичная для JavaScript проблема, связанная с реактивной природой Vue.
https://vuejs.org/v2/guide/reactivity.html
В этом разделе документации обсуждается предостережение об обнаружении изменений Vue:
Vue не может обнаружить добавление или удаление свойства. Поскольку Vue выполняет процесс преобразования getter/setter во время инициализации экземпляра, в объекте данных должно присутствовать свойство, чтобы Vue смог преобразовать его и сделать его реактивным.
Когда во время игры я настраивал игроков так:
gameObj.gameState.players[user.id] = {...playerData}
Я добавляю новое свойство, которое Vue не преобразовало при инициализации, и Vue не обнаруживает это изменение. Это простая концепция, которую я не учел при разработке игры.
Чтобы правильно установить нового игрока, я решил использовать оператор распространения, чтобы изменить players
объект, на который реагирует Vue, и, в свою очередь, Vue обнаружит добавление моего игрока следующим образом:
gameObj.gameState.players = {
...gameObj.gameState.players,
[user.id]: {...playerData}
}
Vue также обсуждает другой метод, называемый $set
, который вы можете прочитать на той же странице.