vue+luckysheet导出功能(解决了样式为null的报错问题)

创建一个js文件存放导出功能代码

javascript 复制代码
import Excel from "exceljs";

import FileSaver from "file-saver";

const exportExcel = function(luckysheet, value) {
  // 参数为luckysheet.getluckysheetfile()获取的对象
  // 1.创建工作簿,可以为工作簿添加属性
  const workbook = new Excel.Workbook();
  // 2.创建表格,第二个参数可以配置创建什么样的工作表
  if (Object.prototype.toString.call(luckysheet) === "[object Object]") {
    luckysheet = [luckysheet];
  }

  luckysheet.forEach((table) => {
    if (table.data.length === 0) return true;
    // ws.getCell('B2').fill = fills.
    const worksheet = workbook.addWorksheet(table.name);
    const merge = (table.config && table.config.merge) || {};
    const borderInfo = (table.config && table.config.borderInfo) || {};
    // 设置单元格宽度
    // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值
    setStyleAndValue(table.data, worksheet);
    setMerge(merge, worksheet);
    setBorder(borderInfo, worksheet);
    return true;
  });

  // return
  // 4.写入 buffer
  const buffer = workbook.xlsx.writeBuffer().then((data) => {
    const blob = new Blob([data], {
      type: "application/vnd.ms-excel;charset=utf-8"
    });
    FileSaver.saveAs(blob, `${value}.xlsx`);
  });
  return buffer;
};

var setMerge = function(luckyMerge = {}, worksheet) {
  const mergearr = Object.values(luckyMerge);
  mergearr.forEach((elem) => {
    // elem格式:{r: 0, c: 0, rs: 1, cs: 2}
    // 按开始行,开始列,结束行,结束列合并(相当于 K10:M12)
    worksheet.mergeCells(
      elem.r + 1,
      elem.c + 1,
      elem.r + elem.rs,
      elem.c + elem.cs
    );
  });
};

var setBorder = function(luckyBorderInfo, worksheet) {
  if (!Array.isArray(luckyBorderInfo)) return;
  luckyBorderInfo.forEach((elem) => {
    if (elem.rangeType === "range") {
      const border = borderConvert(elem.borderType, elem.style, elem.color);
      const rang = elem.range[0];
      const rowStart = rang.row[0] + 1;
      const colStart = rang.column[0] + 1;

      // Apply border to the specified range
      worksheet.getCell(rowStart, colStart).border = border;
    }
    if (elem.rangeType === "cell") {
      const { col_index, row_index } = elem.value;
      const borderData = { ...elem.value };
      delete borderData.col_index;
      delete borderData.row_index;
      const border = addborderToCell(borderData, row_index, col_index);
      worksheet.getCell(row_index + 1, col_index + 1).border = border;
    }
  });
};

var setStyleAndValue = function(cellArr, worksheet) {
  worksheet.columns = [];
  if (!Array.isArray(cellArr)) return;
  cellArr.forEach((row, rowid) => {
    row.every((cell, columnid) => {
      if (!cell) return true;

      // 如果fillConvert返回的是空对象,说明没有填充样式
      const fill = fillConvert(cell.bg);
      const font = fontConvert(
        cell.ff,
        cell.fc,
        cell.bl,
        cell.it,
        cell.fs,
        cell.cl,
        cell.ul
      );
      const alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr);
      let value = "";
      if (cell.f) {
        value = { formula: cell.f, result: cell.v };
      } else if (!cell.v && cell.ct && cell.ct.s) {
        cell.ct.s.forEach((arr) => {
          value += arr.v;
        });
      } else {
        value = cell.v;
      }

      const letter = createCellPos(columnid);
      const target = worksheet.getCell(letter + (rowid + 1));

      // 只有fill不为空对象时才应用
      if (Object.keys(fill).length > 0) {
        target.fill = fill;
      }
      if (Object.keys(font).length > 0) {
        target.font = font;
      }
      // 同样方式检查alignment如果不为空才应用
      if (Object.keys(alignment).length > 0) {
        target.alignment = alignment;
      }

      target.value = value;
      setColumnsWidth(worksheet, rowid);
      return true;
    });
  });
};

var fillConvert = function(bg) {
  if (!bg) {
    return {};
  }
  return {
    type: "pattern",
    pattern: "solid",
    fgColor: { argb: (bg || "#FFFFFF").replace("#", "") }
  };
};

var fontConvert = function(
  ff = 0,
  fc = "#000000",
  bl = 0,
  it = 0,
  fs = 10,
  cl = 0,
  ul = 0
) {
  const luckyToExcel = {
    0: "微软雅黑",
    1: "宋体(Song)",
    2: "黑体(ST Heiti)",
    3: "楷体(ST Kaiti)",
    4: "仿宋(ST FangSong)",
    5: "新宋体(ST Song)",
    6: "华文新魏",
    7: "华文行楷",
    8: "华文隶书",
    9: "Arial",
    10: "Times New Roman ",
    11: "Tahoma ",
    12: "Verdana",
    num2bl: (num) => num !== 0
  };

  const font = {
    name: typeof ff === "number" ? luckyToExcel[ff] : (ff || luckyToExcel[0]),
    family: 1,
    size: fs,
    color: { argb: (fc || "#000000").replace("#", "") }
  };

  // 只有在有意义的值时才添加这些属性
  if (bl) {
    font.bold = luckyToExcel.num2bl(bl);
  }
  if (it) {
    font.italic = luckyToExcel.num2bl(it);
  }
  if (ul) {
    font.underline = luckyToExcel.num2bl(ul);
  }
  if (cl) {
    font.strike = luckyToExcel.num2bl(cl);
  }

  return font;
};

var alignmentConvert = function(
  vt = "default",
  ht = "default",
  tb = "default",
  tr = "default"
) {
  // luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)
  const luckyToExcel = {
    vertical: {
      0: "middle",
      1: "top",
      2: "bottom",
      default: "top"
    },
    horizontal: {
      0: "center",
      1: "left",
      2: "right",
      default: "left"
    },
    wrapText: {
      0: false,
      1: false,
      2: true,
      default: false
    },
    textRotation: {
      0: 0,
      1: 45,
      2: -45,
      3: "vertical",
      4: 90,
      5: -90,
      default: 0
    }
  };

  const alignment = {
    vertical: luckyToExcel.vertical[vt],
    horizontal: luckyToExcel.horizontal[ht],
    wrapText: luckyToExcel.wrapText[tb],
    textRotation: luckyToExcel.textRotation[tr]
  };
  return alignment;
};

function borderConvert(borderType, style = 1, color = "#000") {
  if (!borderType) {
    return {};
  }
  const luckyToExcel = {
    type: {
      "border-all": "all",
      "border-top": "top",
      "border-right": "right",
      "border-bottom": "bottom",
      "border-left": "left"
    },
    style: {
      0: "none",
      1: "thin",
      2: "hair",
      3: "dotted",
      4: "dashDot",
      5: "dashDot",
      6: "dashDotDot",
      7: "double",
      8: "medium",
      9: "mediumDashed",
      10: "mediumDashDot",
      11: "mediumDashDotDot",
      12: "slantDashDot",
      13: "thick"
    }
  };

  const border = {};
  const template = {
    style: luckyToExcel.style[style],
    color: { argb: color.replace("#", "") }
  };

  if (luckyToExcel.type[borderType] === "all") {
    border.top = template;
    border.right = template;
    border.bottom = template;
    border.left = template;
  } else {
    border[luckyToExcel.type[borderType]] = template;
  }

  return border;
}

function addborderToCell(borders, row_index, col_index) {
  const border = {};
  const luckyExcel = {
    type: {
      l: "left",
      r: "right",
      b: "bottom",
      t: "top"
    },
    style: {
      0: "none",
      1: "thin",
      2: "hair",
      3: "dotted",
      4: "dashDot",
      5: "dashDot",
      6: "dashDotDot",
      7: "double",
      8: "medium",
      9: "mediumDashed",
      10: "mediumDashDot",
      11: "mediumDashDotDot",
      12: "slantDashDot",
      13: "thick"
    }
  };
  for (const bor in borders) {
    if (borders[bor].color.indexOf("rgb") === -1) {
      border[luckyExcel.type[bor]] = {
        style: luckyExcel.style[borders[bor].style],
        color: { argb: borders[bor].color.replace("#", "") }
      };
    } else {
      border[luckyExcel.type[bor]] = {
        style: luckyExcel.style[borders[bor].style],
        color: { argb: borders[bor].color }
      };
    }
  }

  return border;
}

function createCellPos(n) {
  const ordA = "A".charCodeAt(0);

  const ordZ = "Z".charCodeAt(0);
  const len = ordZ - ordA + 1;
  let s = "";
  while (n >= 0) {
    s = String.fromCharCode((n % len) + ordA) + s;

    n = Math.floor(n / len) - 1;
  }
  return s;
}

function setColumnsWidth(worksheet, index) {
  /*
  const border = {
    top: {
      style: "thin"
    },
    left: {
      style: "thin"
    },
    bottom: {
      style: "thin"
    },
    right: {
      style: "thin"
    }
  };
  worksheet.columns.map((column) => {
    // 表头的样式
    worksheet.getCell(`${column.letter}1`).border = border;
    // 行数据的样式,移除此默认边框设置
    // worksheet.getCell(`${column.letter}${index + 2}`).border = border;
  });
  */
  worksheet.columns.map((column) => {
    // 列宽自适应(不影响边框设置)
    const width = [];
    column.values.map((value) => {
      if (!value) {
        width.push(10);
      } else if (/.*[\u4e00-\u9fa5]+.*$/.test(value)) {
        width.push(parseFloat(value.toString().length * 2.15));
      } else {
        width.push(parseFloat(value.toString().length * 1.15));
      }
    });
    column.width = Math.max(...width);
  });
}

export {
  exportExcel
};

调用

javascript 复制代码
exportExcel() {
      exportExcel(window.luckysheet.getAllSheets(), `${this.menuName}_${new Date().getTime()}`);
    }
相关推荐
Csvn2 分钟前
性能监控
前端
Highcharts.js4 分钟前
Highcharts Gantt使用符号的自定义数据标签开发甘特图示例
javascript·甘特图·highcharts·图表开发·实战代码·响应式图表
Csvn28 分钟前
构建工具
前端
FRing031 小时前
vue2干货总结3(computed计算属性、watch监听器)
开发语言·前端·vue.js·vue2
Java小卷2 小时前
JuanForm vs FormCreate!Vue3 表单引擎联动配置 PK!
vue.js·低代码
kyriewen3 小时前
Skills 榜前 10 我全装了:只有 3 个能直接用
前端·javascript·程序员
IT_陈寒3 小时前
当Java的hashCode遇上Lombok,我的缓存被全清了
前端·人工智能·后端
工控丫丫4 小时前
帆软看板中经常使用的公式函数及经常搭的组合
前端·javascript·数据库
jerrywus4 小时前
我用 GPT-6.1-sol 做了台会讲解的 3D 售货机:60 罐饮料,一口没喝上
前端·agent·claude
孟陬6 小时前
Foobar 技术周刊#159:当看不懂代码时,如何高效排障调试。脏页陷阱:一条只读查询,写入数 TB 数据。推测解码:大模型加速利器
前端·人工智能·后端