为什么这个Context.Sync不起作用?

为什么这段代码片段不会将值写回Excel,除非我取消注释range.values = range.values行?

$('#run').click(function() { invokeRun() .catch(OfficeHelpers.logError); }); function invokeRun() { return Excel.run(function(context) { var range = context.workbook.worksheets.getItem("Sheet1").getRange("A1:B3"); range.load('values'); return context.sync() .then(function() { range.values[1][1]=99; console.log(JSON.stringify(range.values)); //range.values=range.values return context.sync(); }); }); } 

数组属性是特殊的。 我在我的网站上添加了一个页面来描述主题: 读取和写入数组属性

从这里总结一下代理对象模型的工作方式,无论何时您在某个对象上设置属性,Office.js运行时都会在setter和getter中有一个钩子,用于拦截该调用并将该命令添加到队列。

我们先来看一个常规属性的例子。 根据以上所述,每当你设置一些像range.format.fill.color = "red"东西时,color属性的setter截获请求,并在队列的内部增加一个命令来设置范围填充颜色为红色(将被调度与下一个context.sync

另一方面,如果你所有的都是var color = range.format.fill.color (当然是在loadsync之后),getter将会触发而不是setter,而颜色variables会得到范围的当前值填色。

现在,这是常规的属性。 无论何时设置数组元素 ,都可以有效地访问该数组的值作为getter。 从运行时的angular度来看,这一行与略微更加冗长的版本没有区别:

 var array = range.values; array[r][c] = '-'; 

因为range.values的getter返回的是一个完全普通的JS数组对象,访问它,然后设置它的值没有任何东西传播回原来的Range对象。

如果你想让这些值得到reflection,最好的方法是在同步之后立即获得对数组的引用(例如,var array = range.values,就像上面一样),然后根据需要设置数组的值,然后最后将其设置回对象: range.values = array

这意味着你也可以修改values数组,然后在循环完成时将values属性赋值给自己( range.values = range.values )。 然而,这看起来很尴尬,好像它是无用的,而实际上却不是。 因此,我个人更喜欢在开始时检索数组,然后将其分配给自己的variables,然后进行必要的修改,最后设置完整的数组。

更新澄清以上内容:

非常清楚,通过访问.values.formulas等返回的数组纯粹的vanilla JS数组。 这实际上是问题的症结所在:为了使Office.js返回纯对象,这意味着这些纯对象不能被reflection变化的能力。

对于它的价值,我们实际上有一个即将推出的function,应该在一两个月内推出,我们将在这里介绍一个object.set语法,如下所示:

 range.set({ values: [[1, 2], [3, 4]], format: { fill: { color: "purple" } } } 

这将使在同一对象上设置多个属性更方便,但也可能使数组属性更容易处理。