资讯专栏INFORMATION COLUMN

利用js-xlsx前端导出Excel

muzhuyu / 1158人阅读

摘要:由于项目临时加入导出功能,后台童靴没有多余时间来处理,想前端来处理导出。查询了前端导出方法,大部分是利用来做处理,按照来导出时是没有样式处理的。利用数据导出拿到后端数据,先要对数据进行组装才能导出我们想要的文件格式。

由于项目临时加入导出Excel功能,后台童靴没有多余时间来处理,想前端来处理导出。

查询了前端导出方法,大部分是利用js-xlsx来做处理,按照js-xlsx来导出excel时是没有样式处理的。需要我们来利用该库的专业版本才能设置样式。

这里就需要xlsx-style来处理,给我们的excel文件来添加样式。

利用数据导出

拿到后端数据,先要对数据进行组装才能导出我们想要的文件格式。如果想文件有样式只能利用xlsx-style;

npm install xlsx-style

拷贝下载下来的文件目录dist里的xlsx.core.min.js,引入文件

这里借鉴这位博主主要代码,整理了下,可以实现表头与导出文件名称。

具体调用可以查看DEMO

/**
 * @param {Array} header 表格头部
 * @param {Array} body 表格数据
 * @param {String} title 表格导出名称
 * @param {Boolean} hasTitle 是否需要表格标题
 */
function ExportsEXCL() {
  this.downLoad = ({
    header = [],
    body = [],
    title = "excel",
    hasTitle = false,
  }) => {
    const styleCell = this.setBorderStyle();

    const _headers = header
      .map((v, i) => {
        let key = Object.keys(v);
        return Object.assign(
          {},
          {
            v: `${v[key[0]]}${key[0]}`,
            position: String.fromCharCode(65 + i) + (hasTitle ? 1 : 0)
          }
        );
      })
      .reduce(
        (prev, next) =>
          Object.assign({}, prev, {
            [next.position]: { v: next.v, s: styleCell }
          }),
        {}
      );
    const _body = body
      .map((v, i) =>
        header.map((k, j) => {
          let key = Object.keys(k);
          return Object.assign(
            {},
            {
              v: v[key[0]],
              position: String.fromCharCode(65 + j) + (i + (hasTitle ? 2 : 1))
            }
          );
        })
      )
      .reduce((prev, next) => prev.concat(next))
      .reduce(
        (prev, next) =>
          Object.assign({}, prev, {
            [next.position]: { v: next.v, s: styleCell }
          }),
        {}
      );

    const mergeThead = this.setMergeThead(_headers, hasTitle, title);

    const _merges = this.setTableMerges(header, _headers, hasTitle);

    const _thead = this.setTableThead(mergeThead);

    const output = Object.assign({}, _thead, _body);

    const outputPos = Object.keys(output).sort();

    const ref = outputPos[0] + ":" + outputPos[outputPos.length - 1];

    const wb = {
      SheetNames: ["mySheet"],
      Sheets: {
        mySheet: Object.assign({}, output, { "!ref": ref, "!merges": _merges })
      }
    };

    this.save(wb, `${title}.xlsx`);
  };

  this.setTableThead = wb => {
    for (let key in wb) {
      let i = wb[key].v.indexOf("");
      if (wb[key].v.includes("")) {
        wb[key].v = wb[key].v.substr(0, i);
      }
    }
    return wb;
  };

  // 设置合并表头
  this.setTableMerges = (header, wb, hasTitle) => {
    let _merges = [];
    let len = header.length - 1;
    if (hasTitle) {
      let o = {
        s: {
          c: 0,
          r: 0
        },
        e: {
          c: len,
          r: 0
        }
      };
      _merges.push(o);
    }
    return [..._merges];
  };

  // 设置表头
  this.setMergeThead = (wb, merge, hasTitle, title) => {
    const borderAll = {
      top: {
        style: "thin"
      },
      bottom: {
        style: "thin"
      },
      left: {
        style: "thin"
      },
      right: {
        style: "thin"
      }
    };
    if (hasTitle) {
      wb["A1"] = {
        v: `${title}`,
        s: {
          border: borderAll,
          font: {
            sz: 18,
            bold: true
          },
          alignment: {
            horizontal: "center"
          }
        }
      };
    }
    return wb;
  };

  this.setBorderStyle = () => {
    const borderAll = {
      top: {
        style: "thin"
      },
      bottom: {
        style: "thin"
      },
      left: {
        style: "thin"
      },
      right: {
        style: "thin"
      }
    };
    return { border: borderAll };
  };

  this.save = (wb, fileName) => {
    let wopts = {
      bookType: "xlsx",
      bookSST: false,
      type: "binary"
    };
    let xw = XLSX.write(wb, wopts);
    let obj = new Blob([this.s2ab(xw)], {
      type: ""
    });
    let elem = document.createElement("a");
    elem.download = fileName || "下载";
    elem.href = URL.createObjectURL(obj);
    elem.click();
    setTimeout(function() {
      URL.revokeObjectURL(obj);
    }, 100);
  };

  this.s2ab = s => {
    if (typeof ArrayBuffer !== "undefined") {
      var buf = new ArrayBuffer(s.length);
      var view = new Uint8Array(buf);
      for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
      return buf;
    } else {
      var buf = new Array(s.length);
      for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff;
      return buf;
    }
  };

  // 根据val查询Object key
  this.findKey = (val, obj) => {
    return Object.keys(obj).find(v => obj[v] === val);
  };
}
利用DOM导出

js-xlsx提供了一个直接导出HTML上的DOM表格方法XLSX.utils.table_to_book,但是导出的excel文件时没有任何样式,利用xlsx-style中的xlsx.full.min.js来导出时,没有上面这个方法,后面取了巧。

xlsx-style中的full文件导出来的XLSX改成了STYLEXLSX

引用如下:







利用js-xlsx来导出表格数据,用STYLEXLSX.write来写入数据。

STYLEXLSX.write(
  wb,
  {
    bookType: type == undefined ? "xlsx" : type,
    bookSST: false,
    type: "binary"
  }
)

具体主要代码:

/**
 * 
 * @param {Object} dom table的dom元素
 * @param {Object} name 导出的表名
 * @param {Object} type 导出的类型
 * 
 */
function exportExl(dom, name = "导出数据", type) {
    var wb = XLSX.utils.table_to_book(dom, {sheet: "Sheet JS"});
    var wopts = {
    bookType: "xlsx",
    bookSST: true,
    type: "binary",
    cellStyles: true
    };

    setExlStyle(wb["Sheets"]["Sheet JS"]);
    
    let tmpDown = new Blob(
        [
            this.s2ab(
                STYLEXLSX.write(
                    wb,
                    {
                        bookType: type == undefined ? "xlsx" : type,
                        bookSST: false,
                        type: "binary"
                    } //这里的数据是用来定义导出的格式类型
                )
            )
        ],
        {
            type: ""
        }
    );
    saveAs(
        tmpDown,
        `${name}` +
            "." +
            (wopts.bookType == "biff2" ? "xls" : wopts.bookType)
    );    
}

function saveAs(obj, fileName) {
    let tmpa = document.createElement("a");
    tmpa.download = fileName || "下载";
    tmpa.href = URL.createObjectURL(obj);
    tmpa.click();
    setTimeout(function() {
        URL.revokeObjectURL(obj);
    }, 100);
}    


function s2ab (s){
    if (typeof ArrayBuffer !== "undefined") {
        var buf = new ArrayBuffer(s.length);
        var view = new Uint8Array(buf);
        for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;
        return buf;
    } else {
        var buf = new Array(s.length);
        for (var i = 0; i != s.length; ++i) buf[i] = s.charCodeAt(i) & 0xff;
        return buf;
    }
};

function setExlStyle (data) {  
    
  let borderAll = {  //单元格外侧框线
    top: {
      style: "thin"
    },
    bottom: {
      style: "thin"
    },
    left: {
      style: "thin"
    },
    right: {
      style: "thin"
    }
  }; 
    data["!cols"] = [];
    for (let key in data) {
        if (data[key] instanceof Object) {
            data[key].s = {
                border: borderAll,
                alignment: {
                    horizontal: "center"   //水平居中对其
                },
                numFmt: 0
            }
            data["!cols"].push({wpx: 170});
        }
    }
    return data;
}
缺陷

如果用数据来控制我们的导出,发现配置多级表头时会好复杂,所以没去深究了,用DOM来导出,又发现如果要导出分页表格时只能导出当前页的数据。

而且现在所有的表格都可能不是规范的表格,每个表格结构可能都不相同,只能多带带处理。

当前所有代码查看

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/99098.html

相关文章

  • [SheetJS] js-xlsx模块学习指南

    摘要:简介是前端操作以及类似的二维表的最佳选择之一而是它的社区版本将注意力集中到了数据转换和导出上所以它支持相当多种类的数据解析和导出不仅仅局限于支持格式支持的导入格式支持的导出格式它可以解析符合格式的数据导出符合格式的数据利用中间层操作数据 简介 SheetJS是前端操作Excel以及类似的二维表的最佳选择之一,而js-xlsx是它的社区版本. js-xlsx将注意力集中到了数据转换和导出...

    zhaot 评论0 收藏0
  • 前端实现excel表格导入导出

    摘要:使用时,前端可以将后端返回的数据拼接成自己需要导出的格式,下载到电脑中,完全不依赖后端。 前言 github: https://github.com/stardew516... 以往做excel表格下载功能的时候,都是后端生成好表格后,存储在某个地方,然后给前端一个链接,前端使用a标签加download下载,或者使用node。其实纯前端也是可以做表格下载的,有一个很好用的javascr...

    CoyPan 评论0 收藏0
  • 前端实现Excel导入和导出功能

    摘要:介绍最近项目中让实现一个导入导出的功能,查找了一些插件后发现这个插件,所以就尝试使用了一下,这里将使用方法和遇到的问题简单记录一下。 介绍 最近项目中让实现一个导入导出Excel的功能,查找了一些插件后发现js-xlsx这个插件,所以就尝试使用了一下,这里将使用方法和遇到的问题简单记录一下。 SheetJS js-xlsx 是一款能够读写多种格式表格的插件,浏览器支持良好,并且能在多个...

    Amio 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<