关于#javascript#的问题:说明当前加载的sheet中并不存在该单元格,可能当前单元格被前边合并,这种被合并的单元格也得设置样式


let workbook = XLSX.utils.table_to_book(document.getElementById('mytable'));
            // 先定义列宽 , 我这里文件一共有7 列 ,所以设置7列宽度相等都为 20 ,如果你有很多列建议直接 map()
            let wscols = [
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 },
                { wch: 20 }
            ];
            // 获取 需要设置样式的 sheet ,我这里只有 一个 sheet 所以索引默认加载了第一个
            const sheet = workbook.Sheets[workbook.SheetNames[0]];
            // 设置列宽
            sheet['!cols'] = wscols;

            // 定义框线样式
            const borderAll = {
                color: { auto: 1 },
                top: {style: "thin"},
                bottom: { style: "thin"},
                left: { style: "thin" },
                right: { style: "thin" }
            };

            // 这里的意思为 先默认代表表格的 7 个列  的 列号
            // 比如 A2 意思是 第一列 第2行
            const _letterList = ['A', 'B', 'C', 'D', 'E', 'F', 'G','H','I','J','K','L']
            // 定义一个 箭头函数,接受三个参数,分别为 当前Sheet , 行列号(例如:‘A2’), 是否是新增样式
            const _mapCellStyle = (_sheet, _key, _type) => {
                const _cellStyle = {
                    border: borderAll,
                    alignment: {
                        wrapText: true,
                        horizontal: "center",
                        vertical: "center"
                    },
                    font: {
                        name: "微软雅黑",
                        sz: 10
                    },
                    bold: true,
                    numFmt: "0"
                }

                if (_type === 'append') {
                    // 需要新增样式,说明当前加载的sheet中并不存在该单元格,可能当前单元格被前边合并,这种被合并的单元格也得设置样式,
                    // 否则就会出现 合并单元格只有第一格带框线,后边没框线的情况出现,所以这里需要将后边的边框样式也加上。
                    _sheet[_key] = {
                        s: _cellStyle
                    }
                } else {
                    // 若不是新增样式 则代表sheet中已存在该表格直接修改其 s 属性即可使属性生效
                    if (typeof _sheet[_key] === 'object') {
                        _sheet[_key].s = _cellStyle
                    }
                }
            }

            // sheet 不懂得可以单独打印一下,它其实就是一个对象,键代表行列号(‘A2’),值为该单元格的值,样式等,
            // 我们需要做的就是修改其值中的样式
            Object.keys(sheet).forEach((i, _) => {
                // 无用属性直接过滤
                if (i !== "!ref" || i !== "!cols" || i !== "!merges" || i !== "Am") {
                    // 首先设置遍历到的 当前 key
                    let _nowKey = i
                    // 然后调用 _mapCellStyle  渲染当前单元格样式
                    _mapCellStyle(sheet, _nowKey)
                    // 我们这里先获取下一个行列号  例如当前_nowKey 是 A1  这里就是获取到 B1 ,及 当前行的 下一列数据
                    let _nextKey = _letterList[_letterList.indexOf(_nowKey[0]) + 1] + i.slice(1)

                    // 判断 B1 是否在 Sheet的key中,如果不存在,只可能是因为B1所在单元格已经被A1所合并,所以我们需要将B1也调用一下  _mapCellStyle
                    // 渲染 B1 的样式,不然就会出现 A1 B1 这两格是合并的状态,只有A1有框线,而B1 没有框线的情况。
                    // 这里用 while 就是 要把需要合并的单元格全部 渲染上样式,直到可能 B4 在 Sheet中 停止
                    while (_nowKey[0] !== 'G' && !Object.keys(sheet).includes(_nextKey)) {
                        _mapCellStyle(sheet, _nextKey, 'append')
                        // 这里就是简单的交换索引
                        _nowKey = _nextKey
                        _nextKey = _letterList[_letterList.indexOf(_nowKey[0]) + 1] + _nowKey.slice(1)
                    }
                }
            })

            let wopts = {
                bookType: 'xlsx',
                bookSST: false,
                type: 'buffer',
            }
            console.log(workbook)
            console.log(wopts)
            let _blob = XLSX.write(workbook, wopts);

            window.saveAs(new Blob([_blob], {
                type: "application/octet-stream"
            }), "项目信息一张表.xlsx");

东西都调好了样式没效果求解

如果你想为一个被合并的单元格设置样式,需要先找到合并该单元格的原始单元格,然后为该原始单元格设置样式。

你可以使用JavaScript中的document.querySelector()或document.getElementById()方法来查找该原始单元格。一旦找到了原始单元格,你就可以为它设置样式了。

例如,假设你想为一个被合并的单元格设置背景颜色为黄色,你可以按照以下步骤进行操作:

使用document.querySelector()或document.getElementById()方法找到合并该单元格的原始单元格。

var originalCell = document.querySelector('#original-cell');

为原始单元格设置样式,例如设置背景颜色为黄色。

originalCell.style.backgroundColor = 'yellow';

请注意,如果原始单元格中已经设置了样式,则该样式可能会影响到合并该单元格的单元格。因此,在为合并单元格设置样式之前,最好检查原始单元格中是否已经设置了样式,并在必要时更新该样式。

发完整代码,我测试一下

以下答案由GPT-3.5大模型与博主波罗歌共同编写:
首先看代码中的 _mapCellStyle 函数,可以看到在设置单元格样式时,只有当 _type 参数为 append 时,才会将新的样式应用于单元格。

在代码中,所有单元格的样式都是在遍历到它们时统一设置的,所以任何合并单元格中的单元格都必须在前面遍历到该单元格之后才能生效。

因此,我们需要修改代码,以便在遍历合并单元格中的单元格时,将样式应用于它们。

以下是修改过的代码:

Object.keys(sheet).forEach((i, _) => {
  // 判断当前 key 是否为无用属性,如果是直接 return,否则进行单元格样式处理
  if (i === "!ref" || i === "!cols" || i === "!merges" || i === "Am") return;
  // 先设置遍历到的当前 key
  let _nowKey = i;
  // 先应用样式于当前单元格
  _mapCellStyle(sheet, _nowKey)
  // 再应用样式于合并单元格的单元格
  let mergeCells = sheet['!merges'] || [];
  for (let j = 0; j < mergeCells.length; j++) {
    let startRow = mergeCells[j].s.r;
    let startColumn = mergeCells[j].s.c;
    let endRow = mergeCells[j].e.r;
    let endColumn = mergeCells[j].e.c;
    if (startRow <= _nowKey.slice(1) && _nowKey.slice(1) <= endRow && startColumn <= _letterList.indexOf(_nowKey[0]) && _letterList.indexOf(_nowKey[0]) <= endColumn) {
      let rIndex = Number(_nowKey.slice(1)) - startRow;
      let cIndex = _letterList.indexOf(_nowKey[0]) - startColumn;
      // 合并单元格被拆分为多个单元格时,可能会引起样式问题,所以需要检查索引是否合法
      if (rIndex >= 0 && cIndex >= 0) {
        let mergeKey = _letterList[startColumn + cIndex] + (startRow + rIndex);
        // 如果该单元格未被遍历到,则将样式应用于它
        if (!_mapCellStyle(sheet, mergeKey, 'check')) {
          _mapCellStyle(sheet, mergeKey, 'append');
        }
      }
    }
  }
});

该代码的主要更改是在单元格样式处理的过程中,增加了处理合并单元格的过程,以解决单元格样式不生效的问题。

在这个过程中,我们获取了所有合并单元格的列表(即 sheet['!merges']),并遍历该列表来查找所有包含当前单元格的合并单元格,然后将样式应用于它们。

注意,由于合并单元格可能包含多个单元格,因此我们需要计算当前单元格在合并单元格中的索引,并检查该索引是否为负,并检查合并单元格的单元格是否已经遍历到,以避免重复应用样式。

希望这可以帮助您解决问题。
如果我的回答解决了您的问题,请采纳!

以下内容部分参考ChatGPT模型:


首先,要解决该问题,需要先确认当前加载的sheet中是否存在该单元格,可以使用XLSX.utils.sheet_to_json()方法将sheet转换为JSON格式,然后查找该单元格是否存在于JSON对象中。

若该单元格被前面的单元格合并了,则需要使用XLSX.utils.decode_range()方法解码合并单元格的范围,然后遍历范围内的所有单元格,将它们的样式设置为需要的样式。

以下是代码示例:

// 将sheet转换为JSON格式
let sheet = workbook.Sheets[workbook.SheetNames[0]];
let jsonSheet = XLSX.utils.sheet_to_json(sheet);

// 查找单元格
let cell = "B2"; // 假设需要查找的单元格为B2
let cellFound = jsonSheet.find(obj => obj[cell] !== undefined);

if (cellFound) {
  // 单元格存在,设置样式
  sheet[cell].s = { font: { bold: true } };
} else {
  // 单元格不存在,查找并设置合并单元格的样式
  let range = XLSX.utils.decode_range(sheet["!ref"]);
  for (let i = range.s.r; i <= range.e.r; i++) {
    for (let j = range.s.c; j <= range.e.c; j++) {
      let address = XLSX.utils.encode_cell({ r: i, c: j });
      let cellInfo = jsonSheet.find(obj => obj[address] !== undefined);
      if (cellInfo && cellInfo[cell]) {
        sheet[address].s = { font: { bold: true } };
      }
    }
  }
}

如果我的建议对您有帮助、请点击采纳、祝您生活愉快

各位前辈我用的是短表所以有些单元格式没有数据的会不会是这个原因

可以借鉴下
https://blog.csdn.net/hy840429/article/details/5431733