下面我們通過一示例,來了解一下最常打交道的 Range 對象:
1 /*關於[單元格區域(Range)]對象的測試*/ 2 function Range_Test() { 3 {//1.Range 對象的獲取 4 let rangePathPrinter = rng => Console.log('詳細地址:' + 5 rng.Worksheet.Name + '/' + rng.Address()); 6 7 //1.1.Range 構造器 8 //通過 new 獲取 Range 對象時,默認指向的是 ActiveSheet 表 9 var rngNew = new Range('I1'); 10 rangePathPrinter(rngNew); 11 12 //1.2.通過 Application.InputBox() 方法 13 //當用戶選取了單元格區域並點擊確定時,它返回一個 Range 對象 14 //當用戶未進行任何選取,或者點擊了取消時,它返回 false 15 var rngSelected = Application.InputBox( 16 '請用鼠標框選單元格區域', '選取單元格區域', undefined, 17 undefined, undefined, undefined, undefined, 8); 18 if (rngSelected === false) 19 alert('您未選取任何單元格區域!'); 20 else 21 rangePathPrinter(rngSelected); 22 23 //1.3.通過 Worksheet.Range() 方法獲取,它獲取的單元格區域 24 // 是屬於該 Worksheet(即工作表對象)的 25 var rngWorksheet = ThisWorkbook.Worksheets.Item( 26 ThisWorkbook.Worksheets.Count).Range('A1:A10'); 27 rangePathPrinter(rngWorksheet); 28 29 //1.4.通過 Application.Range() 方法來獲取,它也指向 30 // ActiveSheet(即當前表) 31 let rngApplication = Application.Range('A1'); 32 rangePathPrinter(rngApplication); 33 } 34 35 {//2.Range 的類型原型 36 //由以下語句的結果可知,Range 函數只是一個工具,它 37 //在 new 時,將 prototype 重定向了,它並不是真正的原型 38 Console.log('constructor name : ' + rngNew.constructor.name); 39 Console.log('is instance of Range? = ' + (rngNew instanceof Range)); 40 Console.log('is prototype same? = ' + 41 (rngNew.__proto__ == rngWorksheet.__proto__)); 42 Console.log('is constructor same? = ' + 43 (rngNew.constructor == rngWorksheet.constructor)); 44 } 45 46 {//3.查看 Range 對象的所有成員 47 let memberNames = Object.keys(rngNew); 48 Console.log('property/method count : ' + memberNames.length); 49 let counter = 0; 50 memberNames = memberNames.sort(); 51 for(let name of memberNames) { 52 let info = '[' + (++counter) + ']' + name; 53 //不加try...catch...不行,因為為 member 取值可能出錯 54 try { 55 let member = rngNew[name]; 56 if (/*這個條件判斷不成功,不知為何*/ 57 member instanceof Function || 58 /*這個條件卻可以,奇怪吧*/ 59 typeof member == 'function') 60 Console.log(info + '(...)'); 61 else 62 Console.log(info); 63 } catch { 64 Console.log(info); 65 } 66 } 67 } 68 69 70 {//4.通過 Value()/Value2 快捷讀寫單元格區域 71 //4.1.只能通過 Value2 來寫數據 72 let bordersMaker = function(rng, color) { 73 let indices = [xlEdgeLeft, xlEdgeTop, 74 xlEdgeBottom, xlEdgeRight, 75 xlInsideHorizontal, xlInsideVertical]; 76 for (let index of indices) { 77 (obj=>{ 78 obj.Weight = xlThin; 79 obj.LineStyle = xlContinuous; 80 obj.Color = color; 81 })(rng.Borders.Item(index)); 82 } 83 } 84 //4.1.1.當向包含多個單元格的單元格區域,寫入單個值時, 85 // 每一個單元格都將得到這個值 86 let rngSingleValueWriteTo = new Range('A1:B2,D1,F1:G3'); 87 let red = 255; //紅色 88 bordersMaker(rngSingleValueWriteTo, red); 89 rngSingleValueWriteTo.Value2 = '單個值'; 90 91 //4.1.2.當向一個單元格區域寫入一個一維數組時,它通過遍歷將數組 92 // 中的元素賦值給單元格區域的單元格: 93 // 1.它總是對應的將第N個元素賦值給每行的第N個單元格; 94 // 2.如果它的元素個數多於行的單元格個數,多出的元素將被丟棄; 95 // 3.如果它的元素個數少於行的單元格個數,缺少數據的單元格,將 96 // 被填充以 "#N/A" 這個錯誤 97 let rngSingleDimensionalArrayWriteTo = 98 new Range('A4:B6,D4,F5:I6'); 99 let blue = 12611584; //藍色 100 bordersMaker(rngSingleDimensionalArrayWriteTo, blue); 101 rngSingleDimensionalArrayWriteTo.Value2 = ['a', 'b', 'c']; 102 103 //4.1.3.當向一個單元格區域寫入一個多維數組時,邏輯混亂, 104 // 不要這么調用 105 let rngMultiDimensionalArrayWriteTo = 106 new Range('A8:B10,D8,F8:I9'); 107 let black = 0; //黑色 108 bordersMaker(rngMultiDimensionalArrayWriteTo, black); 109 rngMultiDimensionalArrayWriteTo.Value2 = 110 [['a', 'b', 'c'], [1, 2, 3], [false, true, true]]; 111 112 //4.2.讀取全部單元格區域數據 113 //可以一次性取得單元格區域對象的所有單元格的值,它們會被 114 //組織成一個數組返回,這個數組按照先列后行的數據讀存單元格 115 //區域中所有單元格的值; 116 let rngData = new Range('A12:C15'); 117 rngData.Rows.Item(1).Value2 = ['A', 'B', 'C']; 118 rngData.Rows.Item(2).Value2 = ['D', 'E', 'F']; 119 rngData.Rows.Item(3).Value2 = ['G', 'H', 'I']; 120 //讀取全部 121 let vsData = rngData.Value2; 122 Console.log(JSON.stringify(vsData)); 123 //少讀一列 124 let vsDataPart = rngData.Cells.Item(1) 125 .Resize(3, 2).Value2; 126 Console.log(JSON.stringify(vsDataPart)) 127 //讀單行數據 128 let vsDataRow = rngData.Rows.Item(1).Value2; 129 Console.log(JSON.stringify(vsDataRow)); 130 //讀單列數據 131 let vsDataColumn = rngData.Columns.Item(1).Value2; 132 Console.log(JSON.stringify(vsDataColumn)); 133 //由以上例子的輸出可知,只有單行單元格區域的數據, 134 //可以一次無誤地將所有數據讀取到一個數組中; 135 //而且只要你的單元格區域包含多個單元格,讀取到的 136 //一定會是一個二維數組 137 //綜上所述,請在快捷讀取單元格區域數據時,只按行單行 138 //單行的讀取 139 } 140 141 {/*5.通過 Value()/Value2 讀寫特殊值: 142 //5.1.Date 類型 143 后者將 Date 與 Currency 類型的數據以 Double 類型返回 144 VBA 在這方面處理得比較好,因為它本身支持的 Date/Currency 類型是與 Excel 145 的同名數據類型是對等的;而 JSA 的 Date 類型與 Excel 的 Date 類型完全不對 146 等,至於 Currency 類型,JSA 則根本就不支持*/ 147 let now = new Date(Date.now()); 148 let cell = rngNew; 149 cell.Clear(); 150 //通過賦值加設置數據格式的方式,可以向單元格輸入日期值 151 cell.Value2 = now; 152 cell.NumberFormatLocal = 'yyyy/mm/dd hh:MM:ss;@'; 153 Console.log(cell.Value2.constructor.name);//Number 154 Console.log(cell.Value().constructor.name);//Date 155 let dtValue = cell.Value(); 156 //JSA日期是帶時區的,Excel 的不帶時區 157 Console.log(now); 158 Console.log(now.toLocaleString()); 159 Console.log(dtValue); 160 Console.log(dtValue.toLocaleString()); 161 //設置到單元格的日期數據會丟失毫秒的精度 162 Console.log(now.valueOf()); 163 Console.log(dtValue.valueOf()); 164 Console.log(now - dtValue == now.getMilliseconds()); 165 //所以在 JSA 與 Excel 有日期時間數據交換時,要注意時區與毫秒精度方面的影響 166 } 167 }
其輸出如下:
詳細地址:Sheet2/$I$1 詳細地址:Sheet1/$H$32 詳細地址:Sheet2/$A$1:$A$10 詳細地址:Sheet2/$A$1 constructor name : Range is instance of Range? = false is prototype same? = true is constructor same? = true property/method count : 187 [1]Activate(...) [2]AddComment(...) [3]AddIndent [4]Address(...) [5]AddressLocal(...) [6]AdvancedFilter(...) [7]AllocateChanges(...) [8]AllowEdit [9]Application [10]ApplyNames(...) [11]ApplyOutlineStyles(...) [12]Areas [13]AutoComplete(...) [14]AutoFill(...) [15]AutoFilter(...) [16]AutoFit(...) [17]AutoFormat(...) [18]AutoOutline(...) [19]BorderAround(...) [20]Borders [21]Calculate(...) [22]CalculateRowMajorOrder(...) [23]Cells [24]Characters(...) [25]CheckSpelling(...) [26]Clear(...) [27]ClearComments(...) [28]ClearContents(...) [29]ClearFormats(...) [30]ClearHyperlinks(...) [31]ClearNotes(...) [32]ClearOutline(...) [33]Column [34]ColumnDifferences(...) [35]ColumnWidth [36]Columns [37]Comment [38]Consolidate(...) [39]Copy(...) [40]CopyFromRecordset(...) [41]CopyPicture(...) [42]Count [43]CountLarge [44]CreateNames(...) [45]CreatePublisher(...) [46]Creator [47]CurrentArray [48]CurrentRegion [49]Cut(...) [50]DataSeries(...) [51]Delete(...) [52]Dependents [53]DialogBox(...) [54]DirectDependents [55]DirectPrecedents [56]Dirty(...) [57]DiscardChanges(...) [58]DisplayFormat [59]EditionOptions(...) [60]End(...) [61]EntireColumn [62]EntireRow [63]Errors [64]ExportAsFixedFormat(...) [65]FillDown(...) [66]FillLeft(...) [67]FillRight(...) [68]FillUp(...) [69]Find(...) [70]FindNext(...) [71]FindPrevious(...) [72]FlashFill(...)