vue.js - 包含循环引用的对象图上的 Vue 反应性
问题描述
首先是一些上下文:
我正在构建一个基于 VueJS 的扫雷应用程序。我的网格是一个对象树:每个 Box 对象都有一个“邻居”属性,其中包含 Box 对象,这些对象是下一个框。
结构是圆形的,但很好。
现在的问题:
首先,我尝试在一个小网格(5x5)上运行良好,但是在尝试生成更大的网格(50x50)时,Vue 在设置观察者时产生了“超出最大调用堆栈大小”错误,这是日志
这棵树似乎太大了,vue 无法处理反应性。
冻结我的对象时已确认它工作得很好(没有调用堆栈错误):
data() {
const game = new MinesWheeper(30, 30, 40)
Object.freeze(game)
return {
game
}
}
但是由于冻结,反应性(显然)下降了。尽管如此,我需要反应来显示点击框。
现在这是我发现的问题/线索:
您是否曾经遇到过 Vue 的调用堆栈问题,或者我错过了什么?
有没有办法在具有这种对象结构的 VueJS 上进行反应性工作?(VueX 是解决方案的一部分吗?我真的不知道)
还是我应该考虑使用 VueJS 以外的东西?(用香草做吗??)
提前谢谢,如果我的帖子很乱,对不起,这是我 5 年来的第一篇文章,我很紧张哈哈
编辑:这是一个游戏对象的样子:
game: { // MinesWheeper
_grid: { // Grid
"_bombsNumber": 40
_boxes: [ // Array of Box
{
"_hasBomb": true
"_index": 0
"_isRevealed": false
"_neighbors": [Box, Box, Box, Box]
"hasBomb": true
"index": 0
"isRevealed": false
"nearBombs": 1
}
]
}
}
此外,在点击一个盒子时,我需要: - 如果 Box.hasBomb 为真,则结束游戏 - 显示内容(如果里面没有炸弹) - 如果 Box.nearBombs 等于 0,则传播reveal()调用
我的 Box.reveal() 方法是递归的:
reveal() {
if (this._isRevealed) return
this._isRevealed = true
if (this.hasBomb) {
console.log('Game over')
} else if (this.nearBombs === 0) {
this._neighbors.forEach(neighbor => {
neighbor.reveal()
})
}
}
这就是为什么我认为我需要反应性来更新每个 Box.reveal 调用的视图
解决方案
因此,您有 Box 对象的一维数组,并且每个对象都包含neighbors
数组,其中包含对其相邻 Boxes 的引用(对主数组项)。
您可以使用Object.defineProperty()
创建neighbors
属性,configurable: false
而 Vue 将无法在其上设置响应性。但是其余的 Box 对象属性仍然是反应式的。
我自己设置了一个小演示。所有重要的都在components/HelloWorld.vue
组件中。
示例很少令人费解,因为使用数组可以通过索引轻松引用“prev”和“next”元素,但我需要在对象之间引入循环引用。
在我的机器上,它会在数组中有 10000 个项目时引发错误。但是,如果您切换错误的this.setupRelatioships(boxes);
呼叫this.setupRelatioshipsWithProperties(boxes);
就会消失。
setupRelatioships(boxes) {
for (let i = 0; i < boxes.length; i++) {
boxes[i].prev = i > 0 ? boxes[i - 1] : null;
boxes[i].next = i < boxes.length - 1 ? boxes[i + 1] : null;
}
},
setupRelatioshipsWithProperties(boxes) {
const opts = {
configurable: false,
enumerable: true,
writable: true
};
for (let i = 0; i < boxes.length; i++) {
Object.defineProperty(boxes[i], "prev", {
...opts,
value: i > 0 ? boxes[i - 1] : null
});
Object.defineProperty(boxes[i], "next", {
...opts,
value: i < boxes.length - 1 ? boxes[i + 1] : null
});
}
},
先前引用的Demo(感谢Guillaume Chau)
推荐阅读
- sql-server - SSIS正确处理传入文件的未知时间
- c# - 如何为文本聚类绘制向量空间模型?
- powershell - 在powershell中比较两个csv文件时我在哪里出错?
- javascript - 仅对一个元素主动应用
- json - 以漂亮格式获取 git 日志输出
- java - Java 8 流映射
> 每个键的值总和 - node.js - 如何在带有嵌入文档的 MongoDB 中正确使用聚合?
- java - JPA 和 Oracle 12 中的 @Lob 注释
- java - Crashlytics 如何找到崩溃的确切来源
- excel - Excel:将值向下复制一列,直到另一列中的第一个空白单元格?