我创建了一个小函数,使用 Office javascript api 将一行移动到另一个工作表,但遇到了一个小问题。我用删除线文本标识所有行,然后将它们移动到存档表中。问题似乎出在线路上
dataRange.getRow(row).moveTo(targetSheet.getRange("A" + tglastrowindex));
如果此行被注释掉,则变量 tglastrowindex 在 for 循环的每次迭代中都会正确递增,但如果启用该行,则该行会正确移动,但 tglastrowindex 变量不会递增,因此它会覆盖该行,而不是在该行的最后一行之后添加存档表。
不太确定是什么原因造成的,但可能与行移动有关?有人以前遇到过这个问题或者可以帮忙解决吗?
async function archive() {
await Excel.run(async (context) => {
worksheet = context.workbook.worksheets.getActiveWorksheet();
await context.sync();
console.log("archiving");
let myUsedRange = worksheet.getUsedRange();
let lastrow = myUsedRange.getLastRow().load(["rowindex", "values"]);
await context.sync();
let lastrowindex = lastrow.rowIndex + 1;
//console.log(JSON.stringify(lastrow.rowIndex + 1, null, 4));
let dataRange = worksheet.getRange("A5:M" + lastrowindex).load(["rowCount", "rowIndex"]);
await context.sync();
var tglastrowindex = 0;
var targetSheet;
var tgUsedRange;
var tglastrow;
var cnt = 0;
for (var row = 0; row < dataRange.rowCount; row++) {
//dataRange.getRow(row).format.fill.clear();
//console.log("tglastrowindex1:" + tglastrowindex);
let dataCell = dataRange.getCell(row, 1).load(["format/font/strikethrough"]);
await context.sync();
//console.log(JSON.stringify(dataCell, null, 4));
if (dataCell.format.font.strikethrough == true) {
//console.log("strikethrough detected");
worksheet.load("name");
await context.sync();
//console.log("sourcesheetname:" + worksheet.name);
if (worksheet.name == "Sheet1") {
//console.log("worksheet detected");
targetSheet = context.workbook.worksheets.getItem("Archive").load("name");
await context.sync();
//console.log("targetsheet name:" + targetSheet.name);
tgUsedRange = targetSheet.getUsedRange();
tglastrow = tgUsedRange.getLastRow().load(["rowindex", "values"]);
await context.sync();
if(cnt == 0){
tglastrowindex = tglastrow.rowIndex + 1;
cnt = cnt + 1;
}
else {
tglastrowindex = tglastrowindex + 1;
}
console.log("targetsheet index:" + tglastrowindex);
dataRange.getRow(row).moveTo(targetSheet.getRange("A" + tglastrowindex));
}
}
}
});
首先,我会投票赞成问题,但它不包括最小的、可重现的示例。一个好的问题应该包含一个“创建数据”代码示例,这样我们就可以创建数据,然后创建问题。
参见 --> https://stackoverflow.com/help/minimal-reproducible-example
我在问题中创建示例数据的另一个示例 --> 自定义排序列 - Excel Javascript - Office-JS
同样,关于您的代码,我看到很多
context.sync
,这是应该避免的,特别是在循环内部。不幸的是,无法加载范围内的单个单元格格式属性,因此您必须对每个单元格进行批量同步调用。我没有测试这段代码,比如 >50K 行,但是如果您的工作簿太大并且需要批量同步并循环下面构建 st_rows_arr_of_ri
数组的整个代码,您将会遇到问题。
参见 --> 使用 Office.js 在 Excel 中获取单个单元格格式?
关于您的问题,对我来说突出的一个问题是您对
A1
范围格式约定的使用。尝试仅在使用范围时使用数字,例如 getRangeByIndexes
。在开始写入之前,您只需要找到 Archive
工作表的最后一行一次,然后您就可以跟踪内存中的 lastrow
并递增,而无需检查/同步每个循环/写入。
这是我最终得到的一些示例代码,这就是我如何从整体上解决上述问题。非常通用,我没有从现有工作表中删除这些行,如果是这样,您可能会想要反向执行此操作,并且我为下面的某些代码提供了外部函数,但我在本示例中将其全部构建在一个函数中。
var ws = context.workbook.worksheets.getActiveWorksheet();
//Create fake data
ws.getRange("A1:C10").values = "TEST"
ws.getRange("A2:C2").format.font.strikethrough = true
ws.getRange("A10:C10").format.font.strikethrough = true
await context.sync()
//Get UsedRng rowCount/Index
var Used_Rng_And_Props = ws.getUsedRange(true);
var load_opts_arr = [
"rowCount",
"rowIndex",
];
Used_Rng_And_Props.load(load_opts_arr)
await context.sync();
//Sync up cell formats array
var cell_formats_arr = []
//https://stackoverflow.com/questions/35647790/get-individual-cell-formats-in-excel-using-office-js
var load_opts_arr = [
"format/font/strikethrough",
"rowIndex",
]
for (let ri = Used_Rng_And_Props.rowIndex; ri < Used_Rng_And_Props.rowCount; ri++) {
cell_formats_arr.push(ws.getRangeByIndexes(ri, 0, 1, 1).load(load_opts_arr))
}
await context.sync()
//Get all row indexes w/ cells in Column 0 with strikethrough text
var st_rows_arr_of_ri = []
for (let ai = 0; ai < cell_formats_arr.length; ai++) {
var cell = cell_formats_arr[ai]
if (cell.format.font.strikethrough == true) {
st_rows_arr_of_ri.push(cell.rowIndex)
}
}
var cell_formats_arr = null
//Get Dest Sheet and add Fake Data
var targetSheet = context.workbook.worksheets.add("archive")
targetSheet.getRange("A1:A3").values = "FakeExistingData"
await context.sync()
//Get Dest Sheet Last Row
var targetSheet_Used_Rng_And_Props = targetSheet.getUsedRange(true)
var load_opts_arr = [
"rowCount",
"rowIndex",
];
targetSheet_Used_Rng_And_Props.load(load_opts_arr)
await context.sync()
var row_ct = targetSheet_Used_Rng_And_Props.rowIndex + targetSheet_Used_Rng_And_Props.rowCount
//Move Data
for (let ai = 0; ai < st_rows_arr_of_ri.length; ai++) {
var ri = st_rows_arr_of_ri[ai]
console.log('ri: ' + ri)
var src_rng = ws.getUsedRange(true).getRow(ri)
var dst_rng = targetSheet.getRangeByIndexes(row_ct, 0, 1, 1) //Use getRangeByIndexes to remove need for row 0 check for A1 rng format
src_rng.moveTo(dst_rng);
row_ct = row_ct + 1
}
await context.sync()