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

歡迎訪問 生活随笔!

生活随笔

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

vue

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

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

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

1.需求場景:

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

2.使用工具:

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

3.開始使用:

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

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

npm run dev

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

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


然后生成的最新文件使用file-saver下載下來即可

修改后的源碼文件如下:

第一步:準備源碼:
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;

注意事項:
由于我們發(fā)送axios請求修改了responseType:‘a(chǎn)rraybuffer’,所以我們需要保證此項配置成功,如果項目中使用了mock并引用了就要注意了,因為mock會將全局的axios的responseType設(shè)置為 ’ ';導(dǎo)致我們發(fā)請求無法獲取excel的模板文件內(nèi)容,所以我們需要保證項目中沒有使用mock
第二步:準備模板文件
我們將所有的模板文件都放到項目中的public目錄下即可通過axios直接請求到了(模板文件可以在先安裝xlsx-chart,然后在node_modules中里面拿出來,然后把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)出帶圖標的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>

第四步:最終效果

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

2.生成圖表

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

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

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

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

總結(jié)

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

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