[TOC] > Wed May 26 2021 22:00:24 GMT+0800 (GMT+08:00) 本节涉及 Javascript Array 对象的相关知识,不熟悉的小伙伴可以多研究下 Array 的相关属性和方法。 本小节来看看单元格区域的 Value() 吧。测试数据如表: _|A|B|C --|--|---|-- 1|A|B|C 2|D|E|F 3|G|H|I ## 测试 这里测试3种情形。行列混合;单行;单列。 ### 行列混合 ```js function t(){ let rng = Range("A1:C3") let rng_address = rng.Address() // 单元格区域地址 let rng_value = rng.Value() // 单元格区域的值 Console.log(`${rng_address}==>${JSON.stringify(rng_value)}`) } ``` 结果: ``` $A$1:$C$3==>[["A","B","C"],["D","E","F"],["G","H","I"]] ``` ### 单行测试 ```js function t(){ let rng = Range("A1:C1") let rng_address = rng.Address() let rng_value = rng.Value() Console.log(`${rng_address}==>${JSON.stringify(rng_value)}`) } ``` 结果: ``` $A$1:$C$1==>[["A","B","C"]] ``` 挺正常的。 ### 单列测试 ```js function t(){ let rng = Range("A1:A3") let rng_address = rng.Address() let rng_value = rng.Value() Console.log(`${rng_address}==>${JSON.stringify(rng_value)}`) } ``` 结果: ``` $A$1:$A$3==>[["A"],["D"],["G"]] ``` ## 结论 以 **`行`** 作为基础数组对象来描述多行列单元格区域。有几行就有几个子数组对象,也可以看作有几行就有几个内嵌`[]`。行内的单元格均被 `[]`包裹。 > 这符合人们常规理解的表格行、列结构的描述逻辑。在早期版本的 wps js宏中没有体现这一点。 1. 行内单元格的值被 `[]` 包裹;被子数组对象包含的值均在同一行。 ## 扁平化 > 这部分涉及 JavaScript Array 对象的扁平化处理知识。参考:`Array.prototype.flat()` 方法。 虽然现在的单元格区域的值容易理解,但我们还是稍稍再拓展下。 1. 按照结论,比如单个单元格的值可以描述为 `[["A"]]`,扁平化之后得到 `"A"`;所以单个单元格的值不是数组对象而是具体的值。 >示例: ```js function t2(){ let arr = [["A"]] Range("A4").Value2 = arr; } ``` 2. 比如 `["A", "B", "C"]` 可以看作 `[["A", "B", "C"]]` 扁平化之后的结果,表示 1 行内连续的 3 个单元格。 3. 虽然经过 `Array.flat()` 处理之后,`[["A"], ["B"], ["C"]]`(表示 3 行 1 列) 也能变成 `["A", "B", "C"]`。但根据结论,这样处理后行、列结构已经变化,变成了 1 行 3 列。 从以上几点可以看出,在单元格区域中,`[]`是单元格的核心结构,你做的处理(扁平化、扩展处理)需要注意是否会导致原有单元格区域行、列结构发生变化! > 当然,有时候我们需要这种变化!比如多行变单行。 同时也提示我们:在用 Array 的 flat 方法时应当小心!尤其是在单元格区域读值时。 ## 单元格区域的赋值(写入) 有个通用的方法可以较准确地将数组写入单元格区域: ```js /** * 单元格区域写入 * @param {Array} arr 要写入的数组。 * @param {Range} topRange 要写入的单元格区域的首个单元格 */ function writeArea(arr,topRange){ // 判断首元素是不是数组 // 实质就是判断是否为多行结构 let isArrayItem = Array.isArray(arr[0]) // 如果首元素是数组,即多行。 if(isArrayItem){ // arr.length 行数 // arr[0].length 列数 //(在多行列单元格区域中,每行的列数可定是相同的) topRange.Resize(arr.length, arr[0].length).Value2 = arr; }else{ // 否则为单行多列 topRange.Resize(1,arr.length).Value2 = arr; } } ``` > 这个方法足以应对绝大多数场景,如果参数 arr 的初始数组是比较复杂的结构请自行理顺,使其符合单元格区域的读值的相似结构。 我们接着看下面的例子: ```js function t3(){ let arr = ["A", "B", "C"] Range("E1").Resize(1,3).Value2 = arr // 1 行 3 列;成功赋值 Range("H1").Resize(3,1).Value2 = arr // 3 行 1 列;"B"、"C"丢失,赋值目的未达到 } ``` 从例子可以看出,能否将数组内的元素完整写入目标单元格区域,取决于**数组结构所表示的行、列结构** 与 **目标单元格行、列结构是否一致**。 ### 拓展数组行、列结构 有时候数组内的元素不能满足我们写入单元格区域的行列结构,我们可以数组进行拓展。 #### 单行变多行 单行单元格区域怎么变多行单元格区域,看例子: ```js function t4(){ let arr = ["A", "B", "C"] let brr = arr.map(e=>[e]) // [["A"], ["B"], ["C"]] Range("R1").Resize(brr.length, 1).Value2 = brr } ``` #### 多行变单行 我们用开头的例子: ```js function R2C(){ let arr = [["A", "B", "C"], ["D", "E", "F"], ["G", "H", "I"]] let brr = arr.flat() Range("L1").Resize(brr.length, 1).Value2 = brr.map(e=>[e]); } ``` 变成每行两格: > 自行导入 lodash.js 或者自行解决数组分组的问题。 ```js function R1C2(){ let arr = [["A", "B", "C"], ["D", "E", "F"], ["G", "H", "I"]] let brr = arr.flat() // 偷懒,使用 lodash.js 的 chunk 方法 let crr = _.chunk(brr,2) // [["A", "B"], ["C", "D"],...] Range("K1").Resize(crr.length, crr[0].length).Value2 = crr; } ```