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()}`);
    }
相关推荐
菜鸟una1 小时前
【微信小程序 + 高德地图API 】键入关键字搜索地址,获取经纬度等
前端·vue.js·微信小程序·小程序·typescript
进取星辰3 小时前
33、魔法防御术——React 19 安全攻防实战
前端·安全·react.js
海天胜景3 小时前
vue3 el-table 行号
javascript·vue.js·ecmascript
小赖同学啊3 小时前
深度解析 Element Plus
前端·javascript·vue.js
二十雨辰3 小时前
[CSS3]百分比布局
前端·html·css3
大大。3 小时前
Vue3 与 Vue2 区别
前端·面试·职场和发展
EndingCoder3 小时前
从零基础到最佳实践:Vue.js 系列(3/10):《组件化开发入门》
前端·javascript·vue.js
Mr.app3 小时前
关于Vue自定义组件封装的属性/事件/插槽的透传问题
vue.js
北辰浮光3 小时前
[Vue]路由基础使用和路径传参
前端·javascript·vue.js