日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > vue >内容正文

vue

【xlsx-chart】Vue项目中导出Excel表格并带上图表

發(fā)布時(shí)間:2023/12/20 vue 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【xlsx-chart】Vue项目中导出Excel表格并带上图表 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Vue項(xiàng)目中導(dǎo)出Excel表格并帶上圖表

1.需求場(chǎng)景:

我們?cè)陂_(kāi)發(fā)過(guò)程中會(huì)遇到一些需求就是將表格中的數(shù)據(jù)導(dǎo)出到excel文件中并下載至本地,但目前基本上下載的excel文件只有簡(jiǎn)單的表格數(shù)據(jù),沒(méi)有相關(guān)的圖表(如餅圖,柱狀圖等),當(dāng)我們excel文件中帶上了這些圖表,可以幫助用戶更加簡(jiǎn)潔明了地看到數(shù)據(jù)間的關(guān)系;

2.使用工具:

xslx-chart插件,由于xslx-chart是一個(gè)node環(huán)境下的一個(gè)插件所以我們可以使用兩種方法來(lái)使用它,下文就如何使用xslx-cahrt進(jìn)行介紹(著重介紹方法二)

3.開(kāi)始使用:

方法一:基于node環(huán)境使用xslx-chart工具;
注意:由于xslx-chart是在nodejs環(huán)境下運(yùn)行的,所以我們要在項(xiàng)目本地跑一個(gè)node服務(wù)來(lái)使用xslx-cahrt,
思路:
1.我們?cè)谶\(yùn)行項(xiàng)目的同時(shí),在本地跑一個(gè)nodejs服務(wù)(xlsx-chart-serve),在該nodejs服務(wù)中處理表格的操作,處理完之后再將文件發(fā)送到前端,前端再進(jìn)行文件下載;

如圖:我們跑項(xiàng)目時(shí)直接執(zhí)行

npm run dev

就會(huì)同時(shí)執(zhí)行serve和xlsx;xlsx作用就是將導(dǎo)出表格的服務(wù)跑起來(lái);
注意:
同時(shí)執(zhí)行多個(gè)指令需要concurrently這個(gè)工具,使用 && 連接兩個(gè)指令是串行的,會(huì)中斷執(zhí)行命令
2.我們服務(wù)跑起來(lái)之后,前端需要導(dǎo)出表格時(shí),將數(shù)據(jù)發(fā)送給nodejs服務(wù),交由xlsx這個(gè)服務(wù)處理,處理完之后將文件發(fā)給前端
注意:
由于node服務(wù)和我們項(xiàng)目自身的端口不一致,所以會(huì)導(dǎo)致跨域的問(wèn)題,這個(gè)需要注意

方法二(推薦):基于xlsx-chart進(jìn)行二次開(kāi)發(fā),直接在前端中使用
思路:
我們看xlsx-chart工具的源碼不難發(fā)現(xiàn),它生成的圖表是在本地讀取模板文件然后再拿最新的數(shù)據(jù)去替換模板表格中的數(shù)據(jù)生成的新表格和新圖表,它在node環(huán)境中使用的是fs工具讀取文件,那我們可以在前端使用axios請(qǐng)求本地文件,只要讀取文件內(nèi)容和類型一致就可以了
重點(diǎn): axios請(qǐng)求中響應(yīng)數(shù)據(jù)類型需要配置;將responseType設(shè)置為’arraybuffer’


然后生成的最新文件使用file-saver下載下來(lái)即可

修改后的源碼文件如下:

第一步:準(zhǔn)備源碼:
base.js

var _ = require("underscore"); var Backbone = require("backbone"); var JSZip = require("jszip"); var xml2js = require("xml2js"); var VError = require("verror"); var axios = require('axios'); // var fs = require ("fs"); var async = require("async"); var Chart = Backbone.Model.extend({/*Read XML file from xlsx as object*/read: function (opts, cb) {var me = this;var t = me.zip.file(opts.file).asText();var parser = new xml2js.Parser({ explicitArray: false });parser.parseString(t, function (err, o) {if (err) {return new VError(err, "getXML");}cb(err, o);});},/*Build XML from object and write to zip*/write: function (opts) {var me = this;var builder = new xml2js.Builder();var xml = builder.buildObject(opts.object);me.zip.file(opts.file, new Buffer(xml), { base64: true });},/*Get column name*/getColName: function (n) {var abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";n--;if (n < 26) {return abc[n];} else {return abc[(n / 26 - 1) | 0] + abc[n % 26];}},/*Get shared string index*/getStr: function (s) {var me = this;if (!me.str.hasOwnProperty(s)) {throw new VError("getStr: Unknown string: " + s);}return me.str[s];},/*Write table*/writeTable: function (cb) {var me = this;me.read({ file: "xl/worksheets/sheet2.xml" }, function (err, o) {if (err) {return cb(new VError(err, "writeTable"));}o.worksheet.dimension.$.ref = "A1:" + me.getColName(me.titles.length + 1) + (me.fields.length + 1);var rows = [{$: {r: 1,spans: "1:" + (me.titles.length + 1)},c: _.map(me.titles, function (t, x) {return {$: {r: me.getColName(x + 2) + 1,t: "s"},v: me.getStr(t)}})}];_.each(me.fields, function (f, y) {var r = {$: {r: y + 2,spans: "1:" + (me.titles.length + 1)}};var c = [{$: {r: "A" + (y + 2),t: "s"},v: me.getStr(f)}];_.each(me.titles, function (t, x) {c.push({$: {r: me.getColName(x + 2) + (y + 2)},v: me.data[t][f]});});r.c = c;rows.push(r);});// table的數(shù)據(jù)o.worksheet.sheetData.row = rows;console.log('o',o,rows)me.write({ file: "xl/worksheets/sheet2.xml", object: o });cb();});},/*Write strings*/writeStrings: function (cb) {var me = this;me.read({ file: "xl/sharedStrings.xml" }, function (err, o) {if (err) {return cb(new VError(err, "writeStrings"));}o.sst.$.count = me.titles.length + me.fields.length;o.sst.$.uniqueCount = o.sst.$.count;var si = [];_.each(me.titles, function (t) {si.push({ t: t });});_.each(me.fields, function (t) {si.push({ t: t });});me.str = {};_.each(si, function (o, i) {me.str[o.t] = i;});o.sst.si = si;me.write({ file: "xl/sharedStrings.xml", object: o });cb();});},/*Remove unused charts*/removeUnusedCharts: function (o) {var me = this;if (me.tplName != "charts") {return;};var axId = [];function addId (o) {_.each(o["c:axId"], function (o) {axId.push(o.$.val);});};_.each(["line", "radar", "area", "scatter", "pie"], function (chart) {if (!me.charts[chart]) {delete o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:" + chart + "Chart"];} else {addId(o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:" + chart + "Chart"]);};});if (!me.charts["column"] && !me.charts["bar"]) {delete o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"];} elseif (me.charts["column"] && !me.charts["bar"]) {o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"] = o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][0];addId(o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"]);} elseif (!me.charts["column"] && me.charts["bar"]) {o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"] = o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][1];addId(o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"]);} else {addId(o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][0]);addId(o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][1]);};var catAx = [];_.each(o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:catAx"], function (o) {if (axId.indexOf(o["c:axId"].$.val) > -1) {catAx.push(o);};});o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:catAx"] = catAx;var valAx = [];_.each(o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:valAx"], function (o) {if (axId.indexOf(o["c:axId"].$.val) > -1) {valAx.push(o);};});o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:valAx"] = valAx;},/*Write chart*/writeChart: function (cb) {var me = this;var chart;me.read({ file: "xl/charts/chart1.xml" }, function (err, o) {if (err) {return cb(new VError(err, "writeChart"));}var ser = {};_.each(me.titles, function (t, i) {var chart = me.data[t].chart || me.chart;var r = {"c:idx": {$: {val: i}},"c:order": {$: {val: i}},"c:tx": {"c:strRef": {"c:f": "Table!$" + me.getColName(i + 2) + "$1","c:strCache": {"c:ptCount": {$: {val: 1}},"c:pt": {$: {idx: 0},"c:v": t}}}},"c:cat": {"c:strRef": {"c:f": "Table!$A$2:$A$" + (me.fields.length + 1),"c:strCache": {"c:ptCount": {$: {val: me.fields.length}},"c:pt": _.map(me.fields, function (f, j) {return {$: {idx: j},"c:v": f};})}}},"c:val": {"c:numRef": {"c:f": "Table!$" + me.getColName(i + 2) + "$2:$" + me.getColName(i + 2) + "$" + (me.fields.length + 1),"c:numCache": {"c:formatCode": "General","c:ptCount": {$: {val: me.fields.length}},"c:pt": _.map(me.fields, function (f, j) {return {$: {idx: j},"c:v": me.data[t][f]};})}}}};if (chart == "scatter") {r["c:xVal"] = r["c:cat"];delete r["c:cat"];r["c:yVal"] = r["c:val"];delete r["c:val"];r["c:spPr"] = {"a:ln": {$: {w: 28575},"a:noFill": ""}};};ser[chart] = ser[chart] || [];ser[chart].push(r);});/*var tag = chart == "column" ? "bar" : chart;o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][0]["c:ser"] = ser;*/_.each(ser, function (ser, chart) {if (chart == "column") {if (me.tplName == "charts") {o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][0]["c:ser"] = ser;} else {o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"]["c:ser"] = ser;};} elseif (chart == "bar") {if (me.tplName == "charts") {o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][1]["c:ser"] = ser;} else {o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"]["c:ser"] = ser;};} else {o["c:chartSpace"]["c:chart"]["c:plotArea"]["c:" + chart + "Chart"]["c:ser"] = ser;};});me.removeUnusedCharts(o);/*if (me.showVal) {o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:" + tag + "Chart"]["c:dLbls"]["c:showVal"] = {$: {val: "1"}};};*/if (me.chartTitle) {me.writeTitle(o, me.chartTitle);};/*o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"] = o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:barChart"][0];o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:catAx"] = o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:catAx"][0];o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:valAx"] = o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:valAx"][0];delete o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:lineChart"];delete o ["c:chartSpace"]["c:chart"]["c:plotArea"]["c:areaChart"];*/// me.write({ file: "xl/worksheets/sheet2.xml/", object: o });me.write({ file: "xl/charts/chart1.xml", object: o });cb();});},/*Chart title*/writeTitle: function (chart, title) {var me = this;chart["c:chartSpace"]["c:chart"]["c:title"] = {"c:tx": {"c:rich": {"a:bodyPr": {},"a:lstStyle": {},"a:p": {"a:pPr": {"a:defRPr": {}},"a:r": {"a:rPr": {$: {lang: "ru-RU"}},"a:t": title}}}},"c:layout": {},"c:overlay": {$: {val: "0"}}};chart["c:chartSpace"]["c:chart"]["c:autoTitleDeleted"] = {$: {val: "0"}};},/*Set template name*/setTemplateName: function () {var me = this;var charts = {};_.each(me.data, function (o) {charts[o.chart || me.chart] = true;});me.charts = charts;if (charts["radar"]) {me.tplName = "radar";return;};if (charts["scatter"]) {me.tplName = "scatter";return;};if (charts["pie"]) {me.tplName = "pie";return;};if (_.keys(charts).length == 1) {me.tplName = _.keys(charts)[0];return;};me.tplName = "charts";},/*Generate XLSX with chartchart: column, bar, line, radar, area, scatter, pietitles: []fields: []data: {title: {field: value, ...}, ...}*/generate: function (opts, cb) {var me = this;opts.type = opts.type || "nodebuffer";_.extend(me, opts);async.series([function (cb) {me.zip = new JSZip();me.setTemplateName();let path = me.templatePath ? me.templatePath : (__dirname + "template/" + me.tplName + ".xlsx");console.log("path:", path);axios({url: path, //your urlmethod: 'GET',responseType: 'arraybuffer', // important}).then((response) => {console.log('response',response)me.zip.load(response.data);cb();});//也可以使用fetch代替axios //window.fetch(path).then((response) => {// response.arrayBuffer().then(function (buffer) {// // do something with buffer// console.log('response.arraybuffer()', buffer)// me.zip.load(buffer);// cb();// })//});// fs.readFile(path, function (err, data) {// if (err) {// console.error(`Template ${path} not read: ${err}`);// return cb (err);// };// me.zip.load (data);// cb ();// });// fs.readFile(path, function (err, data) {// if (err) {// console.error(`Template ${path} not read: ${err}`);// return cb (err);// };// me.zip.load (data);// cb ();// });},function (cb) {me.writeStrings(cb);},function (cb) {_.each(me.titles, function (t) {me.data[t] = me.data[t] || {};_.each(me.fields, function (f) {me.data[t][f] = me.data[t][f] || 0;});});me.writeTable(cb);},function (cb) {me.writeChart(cb);}], function (err) {if (err) {return cb(new VError(err, "build"));}var result = me.zip.generate({ type: me.type });cb(null, result);});} }); module.exports = Chart;

注意事項(xiàng):
由于我們發(fā)送axios請(qǐng)求修改了responseType:‘a(chǎn)rraybuffer’,所以我們需要保證此項(xiàng)配置成功,如果項(xiàng)目中使用了mock并引用了就要注意了,因?yàn)閙ock會(huì)將全局的axios的responseType設(shè)置為 ’ ';導(dǎo)致我們發(fā)請(qǐng)求無(wú)法獲取excel的模板文件內(nèi)容,所以我們需要保證項(xiàng)目中沒(méi)有使用mock
第二步:準(zhǔn)備模板文件
我們將所有的模板文件都放到項(xiàng)目中的public目錄下即可通過(guò)axios直接請(qǐng)求到了(模板文件可以在先安裝xlsx-chart,然后在node_modules中里面拿出來(lái),然后把xlsx-chart卸載掉) ;模板我們只需要基礎(chǔ)的即可(columnAvg.xlsx,columnGroup.xlsx,columnGroupAvg.xlsx用不上)

第三步:在vue中使用
xxx.vue文件

<template><div id="app"><img alt="Vue logo" src="./assets/logo.png" /><br /><button @click="getChartExcel" style="margin: 0 auto">導(dǎo)出帶圖標(biāo)的excel表格</button></div> </template><script> // xlsx-chart修改后的源碼文件 import XLSXChart from "./utils/base"; import FileSaver from "file-saver";export default {name: "App",methods: {getChartExcel () {let xlsxChart = new XLSXChart();let opts = {chart: "bar",titles: ["Price"],fields: ["Apple", "Blackberry", "Strawberry", "Cowberry", "jasonchen"],data: {Price: {Apple: 10,Blackberry: 5,Strawberry: 15,Cowberry: 20,jasonchen: 2000},},chartTitle: "Area chart",};xlsxChart.generate(opts, function (err, data) {if (err) {console.error(err);} else {let blob = new Blob([data]);FileSaver.saveAs(blob, "chart.xlsx");}});}}, };</script><style> #app {font-family: Avenir, Helvetica, Arial, sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;text-align: center;color: #2c3e50;margin-top: 60px; } </style>

第四步:最終效果

第五步: 進(jìn)階使用:
思路:我們使用過(guò)后不難了解到,xlsx-chart這個(gè)工具的實(shí)現(xiàn)思路就是在需要導(dǎo)出excel時(shí),通過(guò)讀取本地的excel模板文件,然后使用我們想要展示的數(shù)據(jù)去替換模板中表格的數(shù)據(jù),最終達(dá)到圖表生成的效果;但是我們能不能在已有模板的基礎(chǔ)上多加幾個(gè)圖表呢,答案是可以的而且非常簡(jiǎn)單
1.我們打開(kāi)其中一個(gè)模板文件column.xlsx;選中我們想要生成圖表的列(第一列必選),注意要選中全列

2.生成圖表

3.重復(fù)上述操作生成多個(gè)圖表后,把這些生成的圖表剪切到Chart的sheet中,并保存

4.再次導(dǎo)出表格(使用保存后的模板)

文章項(xiàng)目源碼地址:
https://github.com/Jason-chen-coder/Xlsx-EasyExportExcelWithChars
寫(xiě)在最后:

1.以上就是基于xlsx-chart開(kāi)發(fā)excel導(dǎo)出表格數(shù)據(jù)帶圖表的功能,及簡(jiǎn)單的拓展,如果你有更好的思路可以直接修改base.js的源碼和修改excel模板的圖表樣式甚至往模板中新增excel相關(guān)的更多功能等等;
2.文檔中的項(xiàng)目鏈接:https://github.com/Jason-chen-coder/exportExcelForChart
3.xlsx-chart非常強(qiáng)大,我只是基于他base的源碼修改了一下,大佬們可以修改他完整版的源碼來(lái)開(kāi)發(fā)更多的功能

總結(jié)

以上是生活随笔為你收集整理的【xlsx-chart】Vue项目中导出Excel表格并带上图表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。