• 等待提示使用Vue插件Loading;
  • 导出图片需要将图片转换成base64格式,我在后台直接写了个url转base64接口并开启缓存
  • 导出exce支持多层对象读取数据,例如:{a:{b:[{c:1}]}};key可以写成’a.b[0].c’
  • 此前我们应该先引入exceljs插件const ExcelJS = require('exceljs');

由于对js的框架不甚了解,所以只能手写取值逻辑

/*** 多级获取数据* @param key 用点分开* @param data 数据对象*/
export function getData(key, data) {if (data != null && key) {if (key.indexOf('.') > -1) {let keys = key.split('.');let nextKey = key.substr(keys[0].length + 1);let currKey = keys[0];if (currKey.indexOf('[') > -1) {return getData(nextKey, getData(currKey, data))}return getData(nextKey, data[keys[0]]);} else if (key.indexOf('[') > -1) {let currKeyPre = key.substr(0, key.indexOf('['));let indexStart = key.indexOf('[') + 1;let i = Number(key.substr(indexStart, key.length - indexStart - 1));let d = data[currKeyPre];if (d instanceof Array) {return d[i];}return d;} else {return data[key];}}
}

读取ExcelReader(代码相对较少)

  • 使用方法,后面我们有Vue的现成工具可以使用
ExcelReader.instance().setDateFormat(this.dateFormat).parse(file).then(reader => {let data = reader.getData(); // 可以指定获取哪个Sheet和标题位置this.titles = data.titles;this.list = data.list;
});
  • 用到的日期格式方法
export function formatDate(date, fmt) {if (!date) {return "";}if (!fmt) {fmt = 'yyyy-MM-dd';}try {if (typeof date === 'string' && date.indexOf("-") > -1) {date = new Date(date.replace(/-/g, '/'));} else {date = new Date(date);}} catch (e) {console.log(e);}if (date == null || date === '') {return null;}if (/(y+)/.test(fmt)) {fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length));}let o = {'M+': date.getMonth() + 1,'d+': date.getDate(),"h+": date.getHours() % 12 === 0 ? 12 : date.getHours() % 12, //小时"H+": date.getHours(), //小时'm+': date.getMinutes(),'s+': date.getSeconds()};for (let k in o) {if (new RegExp(`(${k})`).test(fmt)) {let str = o[k] + '';fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? str : padLeftZero(str));}}return fmt;
}
export class ExcelReader {static instance() {return new ExcelReader();}workbook = {};sheets = [];dateFormat = "yyyy-MM-dd HH:mm:ss";setDateFormat(format) {this.dateFormat = format;return this;}parse(file) {return new Promise((ok, cancel) => {let loading = Loading.service({lock: true,text: `读取${file.name}...`,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'});this.workbook = new ExcelJS.Workbook();this.workbook.xlsx.load(file, {}).then(res => {let sheets = this.workbook.worksheets;for (let i = 0; i < sheets.length; i++) {let sheet = sheets[i];let sheetData = {name: sheet.name, index: i, rows: []};let rowCount = sheet.rowCount;for (let rowIndex = 1; rowIndex <= rowCount; rowIndex++) {let row = sheet.getRow(rowIndex);let rowData = [];for (let cellIndex = 1; cellIndex <= row.cellCount; cellIndex++) {let cell = row.getCell(cellIndex);// type:2数值,3字符串,4日期,6公式if (cell.type === 4 && cell.value && this.dateFormat) {if (this.dateFormat.toLowerCase() === 'timestamp') {rowData.push(new Date(cell.value).getTime());} else {rowData.push(formatDate(new Date(cell.value), this.dateFormat));}} else {rowData.push(cell.text.trim());}}sheetData.rows.push(rowData);}this.sheets.push(sheetData);}console.log(this.sheets);loading.close();ok(this);}).catch(err => {loading.close();cancel(err);})});}/**@param sheetIndex 指定Sheet 0开始@param titleIndex 指定标题行0开始@param sheetName 如果不为空则sheetIndex失效*/getData(sheetIndex, titleIndex = 0, sheetName) {// 解析let readIndex = 0;if (sheetIndex != null) {readIndex = sheetIndex;}if (sheetName) {readIndex = this.sheets.findIndex(sheet => sheet.name.toLowerCase() === sheetName.toLowerCase());}let sheet = this.sheets[readIndex];if (sheet.data) {return sheet.data;}let titleData = sheet.rows[titleIndex];let list = [];for (let i = titleIndex + 1; i < sheet.rows.length; i++) {let data = {message: '', loading: false};for (let ci = 0; ci < titleData.length; ci++) {data[titleData[ci]] = sheet.rows[i][ci];}list.push(data);}sheet.data = {titles: titleData, list: list};return sheet.data;}
}

导出ExcelBuilder(这里使用上面的getData方法)

  • 将url转换成base64方法(因为跨域问题,我后台自己写的)
export function imageToBase64(url) {return new Promise((ok, cancel) => {api.base64(url).then(res => {const extension = url.split('?')[0].substring(url.split('?')[0].lastIndexOf('.') + 1).toLowerCase();ok({base64: res.data, extension});}).catch(err => {ok();})})
}
  • 下载exceljs生成的工作簿
function openDownloadDialog(url, saveName) {if (typeof url == 'object' && url instanceof Blob) {url = URL.createObjectURL(url); // 创建blob地址}let aLink = document.createElement('a');aLink.href = url;aLink.download = saveName || ''; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效let event;if (window.MouseEvent) event = new MouseEvent('click');else {event = document.createEvent('MouseEvents');event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);}aLink.dispatchEvent(event);
}
  • 真正的导出Excel方法
// 使用方式:ExcelBuilder.buildSheet([],sheetName:'test',titles:[{'key':'name'}],cloWidth:[{col:15}]).write(fileName);
export class ExcelBuilder {static instance() {return new ExcelBuilder();}workbook = new ExcelJS.Workbook();currSheet = null;loading = Loading.service({lock: true,text: `生成中...`,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'});// 生成标题buildTitle(titles) {let sheet = this.currSheet;if (!sheet) {throw Error("不能直接生成标题,请设置currSheet变量");}if (titles) {let keys = Object.keys(titles);let columns = [];let row = sheet.getRow(1);row.height = 25;for (let i = 0; i < keys.length; i++) {let key = keys[i];let config = titles[key];let header = config.header || config;let width = config.width || header.length * 3;let image = config.image || false;let hidden = config.hidden || false;columns.push({header, key, width, image, hidden});let cell = row.getCell(i + 1);cell.fill = {type: 'pattern', pattern: 'solid', fgColor: {argb: 'FFB6DDE8'}};cell.font = {size: 15, bold: true};cell.alignment = {vertical: 'middle', horizontal: 'center'};cell.border = {top: {style: 'thin'},left: {style: 'thin'},bottom: {style: 'thin'},right: {style: 'thin'}};}console.log("标题:", columns);sheet.columns = columns;return columns;}}addImage(cell, images, index, config) {let workbook = this.workbook;let sheet = this.currSheet;return new Promise((o, c) => {if (index >= images.length) {return o();}let width = 1 / images.length;imageToBase64(images[index]).then(data => {if (data) {let image = workbook.addImage(data);// TODO 这的布局可能还有问题sheet.addImage(image, {tl: {col: cell.col - 1 + width * index, row: cell.row - 1},br: {col: cell.col - 1 + width * (index + 1), row: cell.row}});} else {cell.value = {text: images.join(",")};}this.addImage(cell, images, index + 1, config).then(r => o());})})}addCell(value, cell, config) {return new Promise((ok, cancel) => {if (value) {if (config.image) {if (value instanceof Array) {// 如果需要下载图片this.addImage(cell, value, 0, config).then(r => ok());} else {this.addImage(cell, [value], 0, config).then(r => ok());}} else {cell.value = value;return ok();}} else {return ok();}})}addRow(data, row) {let keys = this.currSheet.columns ? this.currSheet.columns.map(c => c.key) : Object.keys(data);let _this = this;let call = (i) => {return new Promise((ok, cancel) => {if (i >= keys.length) {return ok();}let cell = row.getCell(i + 1);cell.alignment = {vertical: 'middle', horizontal: 'center'};let config = _this.currSheet.titles[i];_this.addCell(getData(keys[i], data), cell, config).then(_ => call(i + 1).then(_ => ok()));});};return new Promise((ok, cancel) => call(0).then(_ => ok()));}buildSheet(list = [], {sheetName, titles, defaultRowHeight = 15}) {if (this.loading) {this.loading = Loading.service({lock: true,text: `生成中...`,spinner: 'el-icon-loading',background: 'rgba(0, 0, 0, 0.7)'});}let _this = this;sheetName = sheetName || 'Sheet' + (this.workbook.worksheets.length);return new Promise((ok, cancel) => {let sheet = this.workbook.getWorksheet(sheetName);sheet = sheet || this.workbook.addWorksheet(sheetName);// sheet.properties.defaultRowHeight = defaultRowHeight;this.currSheet = sheet;this.currSheet.titles = this.buildTitle(titles);let startRowNumber = sheet.lastRow.number + 1;if (list && list.length) {let addList = (i) => {return new Promise((ok, cancel) => {if (i >= list.length) {return ok();}let row = sheet.getRow(startRowNumber + i);row.height = defaultRowHeight;let data = list[i];_this.loading.text = `${sheetName},进度:${i + 1}/${list.length}`;_this.addRow(data, row).then(_ => addList(i + 1).then(_ => ok(_this)))});};addList(0).then(_ => {console.log(`${sheetName}生成完成`);_this.loading.close();ok(_this);});} else {_this.loading.close();ok(_this);}})}write(fileName) {console.log("开始下载");let buffer = this.workbook.xlsx.writeBuffer();buffer.then(res => {let blob = new Blob([res], {type: "application/octet-stream"});openDownloadDialog(blob, fileName + '.xlsx');})}
}

接下来是Vue插件,没有用Vue的到此就结束了

  • 读取插件(数据导入功能用到),因为支持错误导出,所以还需要上面的导出功能
// 主要用于下载模板
export function downloadFile(url, fileName = '') {axios.create().request({url: url, responseType: 'arraybuffer'}).then(res => {let blob = new Blob([res.data], {type: 'application/stream'});let objectUrl = URL.createObjectURL(blob);downloadURL(objectUrl, fileName)})
}
  • 使用方法
<read-excel-button :post="doImport":columns="importColumns"template-name="合同导入模板.xlsx"date-format="yyyy-MM-dd"template="导入模板base64格式,带前缀">
</read-excel-button>
<script>
data(){return {importColumns: {"商品名": {required: true, key: 'name', reg: /\s+/,validator:(data,config,value)=>true},
}
}
doImport(data, index) {return new Promise((ok, cancel) => {console.log(data);product.add(data).then(res => {console.log(res);ok();}).catch(err => {console.log(err);cancel(err.msg);});// 解析合同分成})
}
</script>
<template><div style="margin-left:10px;margin-right:10px;display: inline-block;"><el-button @click="selectFile" type="info">{{name}}</el-button><input type="file" ref="file" @change="getFile" style="display: none;" accept=".xlsx"/><el-dialog :title="title" :visible.sync="show" width="90%" @opened="selectAll" top="20px" :close-on-click-modal="false"><el-table id="importTable" :data="list" height="400px" @selection-change="selectionChange" ref="importTable":row-class-name="({row,index})=>row.message?'warning-row':row.loading?'current-row':row.success?'success-row ':''"><el-table-column type="selection" width="55" :selectable="(row)=>!row.disabled"></el-table-column><el-table-column type="index"></el-table-column><el-table-column v-for="title in titles" :label="title" :prop="title" :key="title" :min-width="title.length*15+20"></el-table-column><el-table-column label="状态" prop="message" min-width="100px"><template slot-scope="scope"><div v-if="scope.row.message" style="color:red;">{{scope.row.message}}</div><div v-else-if="scope.row.loading"><i class="el-icon-loading"></i></div><div v-else-if="scope.row.success">完成</div></template></el-table-column></el-table><span slot="footer" class="dialog-footer"><el-button @click="exportError" v-if="errorList.length && !importing" type="warning">导出错误({{errorList.length}})</el-button><el-button @click="show = false" type="danger">关 闭</el-button><el-button type="primary" @click="doImport" :loading="importing">导入</el-button></span></el-dialog></div>
</template><script>import {ExcelBuilder, ExcelReader} from "../utils/excel";import {downloadFile} from "../utils/download";export default {name: "ReadExcelButton",props: {name: {type: String, default: "上传数据"},title: {type: String, default: "数据内容"},post: Function,postAll: Function,template: String, // 模板base64templateName: {type: String,default: '模板下载.xlsx',},dateFormat: {type: String,default: 'yyyy-MM-dd HH:mm:ss', // timestamp},columns: Object, //字段设置与校验 excel标题:{required:false,reg:'正则校验',validator:function(value),key:'将数据复制到字段',formatter:function(value),message:'错误提示'}},data() {return {show: false,titles: [],list: [],selectList: [],importing: false,fileName: this.name,}},computed: {errorList() {return this.list.filter(i => i.error)}},methods: {// 选择文件selectFile() {/// 下载模板提示this.$confirm("请选择操作", '导入数据', {confirmButtonText: '导入数据', cancelButtonText: '下载模板', distinguishCancelAndClose: true, callback: (action, instance) => {if (action === 'confirm') {this.$refs.file.dispatchEvent(new MouseEvent('click'));} else if (action === 'cancel' && this.template) {downloadFile(this.template, this.templateName);}}});},validAndFormat(list) {if (this.columns) {// 验证数据let keys = Object.keys(this.columns);for (let i = 0; i < list.length; i++) {let data = list[i]; // 当前验证数据for (let k = 0; k < keys.length; k++) {let key = keys[k]; // 当前验证字段let value = data[key];let config = this.columns[key]; // 字段配置;reg,validator,key,formatter,messagelet valid = true; // 是否是有效的数据let empty = (value == null || value === '');if (config.required && empty) {valid = false;} else if (config.reg != null && (config.required || !empty)) {if (!RegExp(config.reg).test(value)) {valid = false;}}if (config.validator != null && typeof config.validator === 'function' && valid) {valid = config.validator(data, config, value);}if (!valid) {data.disabled = true;data.error = true;data.message = config.message || `${key},无效数据`;}// 数据格式化if (config.formatter != null && typeof config.formatter === 'function' && valid) {value = config.formatter(data, config, value);}if (config.key != null && config.key) {if (config.key.includes('.')) {let ks = config.key.split(".");if (data[ks[0]] == null) {data[ks[0]] = {};}let lastValue = data[ks[0]];for (let ki = 0; ki < ks.length; ki++) {if (lastValue == null) {data[ks[ki]] = {};}if (ki === ks.length - 1) {lastValue[ks[ki]] = value;} else {lastValue = data[ks[ki]];}}}data[config.key] = value;} else {data[key] = value;}}}console.log("格式化后结果:", list);}},getFile() {let file = this.$refs.file.files[0];this.fileName = file.name.substr(0, file.name.lastIndexOf("."));ExcelReader.instance().setDateFormat(this.dateFormat).parse(file).then(reader => {let data = reader.getData();this.titles = data.titles;this.list = data.list;this.validAndFormat(this.list);this.show = true;// 清空选中文件,下次可以继续选择同样文件this.$refs.file.value = null;});},selectAll() {this.$refs.importTable.toggleAllSelection(this.list.filter(i => !i.disabled));},doImport() {if (this.selectList.length <= 0) {this.$message({message: '请选择数据', type: "warning"});return;}console.log("选中数据:", this.selectList);this.importing = true;if (this.post != null) {let success = [];let tableRowsEle = null;try {let tableEle = document.getElementById('importTable');let tableBodyEle = tableEle.getElementsByClassName('el-table__body')[0];tableRowsEle = tableBodyEle.getElementsByClassName('el-table__row');} catch (e) {console.error(e);}let doPost = (data, index, call) => {if (index >= this.selectList.length) {call();return;}// 滚动到可显示的底部区域if (tableRowsEle) {tableRowsEle[index].scrollIntoView(false);}data.loading = true;this.post(data, index).then(res => {success.push(data);doPost(this.selectList[index + 1], index + 1, call)}).catch(err => {data.message = err;data.error = true;doPost(this.selectList[index + 1], index + 1, call)}).finally(() => {data.loading = false;});};doPost(this.selectList[0], 0, res => {success.forEach((suc) => {this.$refs.importTable.toggleRowSelection(suc);suc.disabled = true;suc.success = true;});this.importing = false;this.$message({type: 'success', message: '导入完成'});this.$emit("success", success);})} else if (this.postAll != null) {this.postAll(this.selectList);}},selectionChange(list) {this.selectList = list;},exportError() {if (this.errorList && this.errorList.length) {let titles = {};for (let i = 0; i < this.titles.length; i++) {let key = this.titles[i];titles[key] = key;}titles['message'] = '状态';ExcelBuilder.instance().buildSheet(this.errorList, {titles}).then(workbook => {workbook.write(this.fileName + '-错误数据');})} else {this.$message({type: 'error', message: '没有错误字体'})}}}}
</script><style scoped>.el-table >>> .warning-row {background: #f7b4ad;}.el-table >>> .current-row {background-color: #ceffaa;}.el-table >>> .success-row {background-color: #e9fbe6;}
</style>

导出数据

  • 支持直接导出el-table数据
  • 支持导出图片
  • 支持导出多个Sheet
  • 涉及到数据格式化需要同getData功能setData
export function setData(key, data, value) {if (key != null) {if (key.indexOf(".") > -1) {let keys = key.split('.');let nextKey = key.substr(keys[0].length + 1);let currKey = keys[0];if (currKey.indexOf('[') > -1) {let d = getData(currKey, data);if (!d) {d = setData(currKey, data, nextKey ? {} : value);}return setData(nextKey, d, value)}if (!data[keys[0]]) {data[keys[0]] = {};}return setData(nextKey, data[keys[0]], value);} else if (key.indexOf('[') > -1) {let currKeyPre = key.substr(0, key.indexOf('['));let indexStart = key.indexOf('[') + 1;let i = Number(key.substr(indexStart, key.length - indexStart - 1));if (!data[currKeyPre]) {data[currKeyPre] = [];}if (data[currKeyPre] instanceof Array) {if (data[currKeyPre].length < i) {for (let j = data[currKeyPre].length; j <= i; j++) {data[currKeyPre][j] = {};}}data[currKeyPre][i] = value;return data[currKeyPre][i];}data[currKeyPre] = value;return data;} else {data[key] = value;return data;}}
}
  • 下面是导出主要功能(具体使用方法在插件中有个示例)
<template><el-button @click="doExport">导出</el-button>
</template><script>import {ExcelBuilder} from "../utils/excel";import {getData, setData} from "../utils";export default {name: "BuilderExcelButton",props: {// 导出配置:{sheetName:'Sheet1',data:[Function,Array],columns,expand,tableRef}config: {type: [Object, Array, Function],default() {return {sheetName: 'Sheet1',data: [{name: '测试',product: {price: 1},channels: [{name: '渠道1', channelId: 1},{name: '渠道2', channelId: 2}]}], // 数组或查询方法tableRef: 'list', // 用于获取表格字段,需要配置对应prop,label属性image: false, // 是否导出图片columns: { // 与tableRef冲突,但是优先级大于tableRef'name': {header: '标题名称',image: false, // 是否下载图片formatter: function (data, column, value) {console.log('格式化数据:', value);return data['name'];}}},// 扩展字段,用于导出不在tableRef中的字段配置expand: {'product.price': {header: '价格'}}}}},name: String, // 导出文件名},data() {return {loading: false,}},methods: {doExport() {this.loading = false;// 解析配置到数组let loadConfig = () => new Promise((ok, cancel) => ok(this.config));if (typeof this.config === 'function') {loadConfig = this.config;}loadConfig().then(config => {let configs = config instanceof Array ? config : [config];console.log("开始导出", config);if (!config) {return;}// 解析标题配置到config.titlesconfigs.forEach((c, i) => this.parseHeaders(c, i));this.exportSheet(configs).then(workbook => {console.log("完成", workbook);this.loading = false;let name = this.name ? this.name : "导出列表";workbook.write(name);}).catch(err => {this.$message({type: 'error', message: '导出失败:' + err})})})},// 解析表格对应的列配置parseTableColumns(tableRef) {if (tableRef) {let refObject = this.parentRefObject(tableRef, this.$parent);if (refObject) {let columns = refObject.tableColumns();let titles = {};columns.filter(c => c.property).forEach(c => {titles[c.property] = {header: c.label, image: c.label.includes("图"), formatter: c.formatter};});return titles;}}return null;},// 解析单个配置文件parseHeaders(config, index) {config.sheetName = config.sheetName || `Sheet${index + 1}`;let titles = config.columns || this.parseTableColumns(config.tableRef);if (titles) {if (config.expand) {let entries = Object.entries(titles);entries.forEach((e, i) => e.index = i);Object.entries(config.expand).forEach(e => entries.push(e));// TODO 根据索引排序标题config.titles = Object.fromEntries(entries);} else {config.titles = titles;}}if (config.titles) {// 重新设置图片属性let keys = Object.keys(config.titles);for (let i = 0; i < keys.length; i++) {let title = config.titles[keys[i]];if (title.image) {title.image = config.image || false;}}}},// 创建SheetexportSheet(configs, index = 0, workbook) {return new Promise((ok, cancel) => {if (index >= configs.length) {return ok(workbook);}console.log("创建数据:", configs[index]);let config = configs[index];let data = config.data;let defaultRowHeight = Object.values(config.titles).find(t => t.image) ? 50 : 15;if (typeof data === 'function') {data().then(list => {data = list;this.formatterData(config.titles, list);(workbook || ExcelBuilder.instance()).buildSheet(list, {titles: config.titles, sheetName: config.sheetName, defaultRowHeight}).then(workbook => {this.exportSheet(configs, index + 1, workbook).then(r => ok(r));})}).catch(err => {this.$message({type: 'error', message: config.sheetName + '导出失败'});this.exportSheet(configs, index + 1, workbook).then(r => ok(r));})} else if (data instanceof Array) {this.formatterData(config.titles, data);(workbook || ExcelBuilder.instance()).buildSheet(data, {titles: config.titles, sheetName: config.sheetName, defaultRowHeight}).then(workbook => {this.exportSheet(configs, index + 1, workbook).then(r => ok(r));})} else {cancel();}})},formatterData(titles, list) {let formatterColumns = Object.entries(titles).filter(c => c[1].formatter != null);for (let i = 0; i < formatterColumns.length; i++) {let key = formatterColumns[i][0];let column = formatterColumns[i][1];let formatter = column.formatter;for (let di = 0; di < list.length; di++) {let data = list[di];let value = getData(key, data);if (formatter != null) {setData(key, data, formatter(data, column, value));}}}},exportList() {let titles = this.columns || this.parseTableColumns();console.log(titles);if (!titles) {this.$message({type: 'error', message: '导出字段配置错误,请联系管理员'});return;}// this.loading = true;this.loadData(titles).then(list => {// 格式化数据let formatterColumns = Object.entries(titles).filter(c => c[1].formatter != null);for (let i = 0; i < formatterColumns.length; i++) {let key = formatterColumns[i][0];let column = formatterColumns[i][1];let formatter = column.formatter;for (let di = 0; di < list.length; di++) {let data = list[di];let value = data[key];if (formatter != null) {data[key] = formatter(data, column, value)}}}console.log(list);console.log(titles);ExcelBuilder.instance().buildSheet(list, {titles}).then(workbook => {this.loading = false;let name = this.name ? this.name : "字体列表";workbook.write(name);})}).catch(err => {});},parentRefObject(ref, parent) {if (parent) {if (parent.$refs[ref]) {return parent.$refs[ref];} else {return this.parentRefObject(ref, parent.$parent)}}return null;}}}
</script><style scoped></style>

写完了,电脑好卡.有疑问请直接留言,我会不定期查看.

使用exceljs读取和导出Excel并支持图片导出相关推荐

  1. java利用poi导出excel功能-附带图片导出

    java利用poi导出excel功能-附带图片导出 写在前面 最近刚离职,闲来无事,于是把上两家公司都有碰到过的需求但都没有去研究实现:即导出带图片的excel报表.于是就折腾了一下这个功能,研究出来 ...

  2. python3 根据sql导出excel文件 支持xls和xlsx

    python3 根据sql导出excel文件 支持xls和xlsx 代码简介: sql_output_excel函数是用来导出excel文件的,其他两个函数是导出xls和xlsx格式的. 使用pymy ...

  3. xlsx模块 前端_利用xlsx-syle前端导出excel且支持自定义样式

    利用xlsx-syle前端导出excel且支持自定义样式 前言 本文的代码是基于react的. 本文仅用于记录我在前端导出excel遇到的问题的笔记整理. 需求描述 需要前端来实现对数据的导出,导出成 ...

  4. vxe-table 导出 excel xlsx wps pdf 导出数据

    vxe-table 导出 excel xlsx wps 导出数据 默认支持的导出格式为:txt.html.xml.cvs 导出 xlsx 如果需要导出为 xlsx 格式文件,就需要用到 exceljs ...

  5. html导出excel 内存不足,web导出excel那些坑

    背景介绍 昨天在一个前端的微信公众号看到一篇文章介绍导出cvs文件的,想想之前做导出excel的踩过的坑,心想记录一下,或许可以帮助别人吧! 需求很简单,在某个报表页面需要把table导出excel. ...

  6. asp.net中使用excel类导出Excel文件,并导出到web客户端中遇到的问题

    asp.net中使用excel类导出Excel文件,并导出到web客户端中遇到错误: 检索Com类工厂中CLSID为{000245-0000-0000-C000-000000000046}的组件失败, ...

  7. 如何按指定名称快速导出Excel中的图片?

    照例举个例子.如下图所示,工作表中存在多张图片,现在需要将其导出,并按图片向左偏移一个单元格,也就是A列单元格的值进行命名. 导出后结果如下图所示: 如果不追求规范图片命名,只是导出Excel中的图片 ...

  8. echarts 图表导出PDF(带滚动条)/图片导出PDF

    echarts 图表导出PDF[带滚动条]/图片导出PDF 效果展示 提出问题 思考问题 解决问题 导出PDF 里面的页头中文乱码问题 参数说明 效果展示 提出问题 在开发过程中,有需求是将展示出来的 ...

  9. js-xlsx/xlsx-style 纯前端数据导出Excel且支持自定义样式

    前端开发过程中经常遇到导出excel的需求.这种情况大多数都是服务端处理数据(QAQ至少我遇到的大多数都是这样),然后返回一个链接,前端不需要管服务端怎么操作直接打开这个链接(window.locat ...

最新文章

  1. 岛屿类-网格类问题-DFS | 力扣200. 岛屿数量
  2. JavaScript 进行数值与对应的 ASCII 字符之间的转换【from​Char​Code、from​Code​Point、charCodeAt、code​PointAt】
  3. Windows Server 2016 Hyper-v 嵌套虚拟化技术
  4. Apache的RewriteRule规则详细介绍
  5. [Quatsch]Quantum Or Optics
  6. 从0基础学Python:装饰器及练习(基础)
  7. Oracle exp/imp导入不同的表空间
  8. SQL Server数据库应用技术
  9. win10+ubuntu16.04双系统下完全删除并重装ubuntu16.04
  10. android 动态表情包,动态表情包下载免费
  11. 如何在计算机自动开机时选择用户,电脑如何设置自动开机
  12. CTF-命令执行漏洞
  13. R语言中创建股票走势图
  14. 直截了当地解释 ERC-3525 与 ERC-1155 的差别
  15. 计算机时间转换工具,计算机时间的转换
  16. java volatile
  17. Establishing Android Build Environment
  18. 什么样的人可以担任项目经理?
  19. 学计算机的有趣软件,这六款实用又有趣的电脑软件你知道几款呢
  20. 10 51单片机汇编:让定时器产生中断(使用Keil模拟器)[系列教程之10]

热门文章

  1. MySQL入门学习的第一节(SQL语句)
  2. numpy数组和图片互转
  3. 记录一次排查Invalid bound statement (not found)问题
  4. [Excel常用函数] sumif sumifs函数
  5. turlebot3 ROS相关求助
  6. MINIO-Bucket数据迁移方案
  7. 全球50大最重要互联网人物
  8. 2022双十一买什么好?行家推荐四大最值得入手的数码好物
  9. 电大本科计算机上机考试题库,国家开放大学电大计算机操作考试题题库及答案...
  10. pytorch中的BatchNorm和LayerNorm