Closed yinfangyan closed 2 years ago
好象对数组的修改不能直接用 this.data.set('list', outer)
一直没找到不那么碎片的时间跟跟看。应该不是 @zhengmz 说的原因。麻烦先用 item 规避
翻了一遍实现,当时写的时候很多思考的点都浮上心头。
先说结论:这个 case,严格来说是 bug。但是不会修复,在当初实现的时候,就考虑到了的。下面是一些说明:
san 的视图更新机制是:将 数据变化对象 沿着组件树向下传递,树中每个节点决定自己子树如何更新。更详细的可以看 https://efe.baidu.com/blog/san-perf/ 。
对于一个 for 节点,它会考虑要向子节点(每个item节点)传递的 数据变化对象 是什么。它向 item 节点传递的数据变化对象,一定是经过处理的。
为了达到较好的性能,for 节点在生成向 item 节点传递的数据变化对象时,有一些处理的考虑,尽量让中间运行的过程,负担小一些。
比如,对于这个 issue 的场景,我要引用当前数据项,我没必要额外在 item 之外,再增加一个 list[index] 的变更表达式信息。因为对于使用者来说,这么玩便利性其实是更差的,而且还带来额外的运行成本(不是实现成本,要实现的话很简单,代码就几行,在这敲这么多字,早实现完了)。
再比如,我引用数组对象上的非数字索引外的属性,更新也会有问题。因为对数组的 immutable 更新过程,如果要考虑 for length 遍历之外的东西,运行成本会很高,而且实际上不应该这么使用数组。所以下面的场景,{{list.p}} 的视图更新也会失败的。
let outer = ['one'];
outer.p = 'p2'
var MyApp = san.defineComponent({
template: `
<div>
<p s-for="item, idx in list"><u>item-{{list[idx]}}</u><b>{{list.p}}</b></p>
<p s-for="item, idx in list"><u>item-{{item}}</u><b>{{list.p}}</b></p>
</div>
`,
initData: function () {
let list = [1];
list.p = 'p';
return {
list
};
},
attached() {
setTimeout(() => {
console.log('before', outer)
this.data.set('list', outer)
this.nextTick(() => {
console.log('after', this.data.get('list'))
})
}, 1000)
}
});
var myApp = new MyApp();
myApp.attach(document.body);
借这个 issue,记录下一点之前实现时候思考过的东西。还有问题,我们再讨论
好的,感谢您如此细致的答疑。
看起来没有疑问,我就关了。如果再发现其他问题,我们再开新issue讨论
示例代码如下:
实际渲染结果:
预期结果
测试了一下只有通过index访问数组获取的值有问题,若是直接使用 item,则结果符合预期