Luckysheet + Exceljs:H5实现Excel在线编辑、导入、导出及上传服务器的示例代码(完整版demo)

 

创建xeditor.html 

<!DOCTYPE html>
<html><head><meta charset="UTF-8" /><title>Hello World!</title><!-- <link rel='stylesheet' href='./luckysheet/plugins/css/pluginsCss.css' /><link rel='stylesheet' href='./luckysheet/plugins/plugins.css' /><link rel='stylesheet' href='./luckysheet/css/luckysheet.css' /><link rel='stylesheet' href='./luckysheet/assets/iconfont/iconfont.css' /><script src="./luckysheet/plugins/js/plugin.js"></script><script src="./luckysheet/luckysheet.umd.js"></script> --><!-- 引入luckysheet,用于渲染表格 --><link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/css/pluginsCss.css' /><link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/plugins.css' /><link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/css/luckysheet.css' /><link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/assets/iconfont/iconfont.css' /><script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/plugins/js/plugin.js"></script><script src="https://cdn.jsdelivr.net/npm/luckysheet@latest/dist/luckysheet.umd.js"></script><!-- 引入exceljs、FileSaver,用于luckysheet表格转xlsx文件 --><script src="https://cdn.bootcdn.net/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script><script src="https://cdn.bootcdn.net/ajax/libs/exceljs/4.3.0/exceljs.js"></script><script>$(function () {//Configuration itemvar options = {container: 'luckysheet', //luckysheet is the container idshowinfobar: false,title: '在线表格', // 设定表格名称lang: 'zh' // 设定表格语言}luckysheet.create(options)});</script>
</head><body><div id="lucky-mask-demo"style="position: absolute;z-index: 1000000;left: 0px;top: 0px;bottom: 0px;right: 0px; background: rgba(255, 255, 255, 0.8); text-align: center;font-size: 40px;align-items:center;justify-content: center;display: none;">download...</div><p style="text-align:center;"> <input style="font-size:16px;" type="file" id="Luckyexcel-demo-file"name="Luckyexcel-demo-file" change="demoHandler" /> 或加载远程 xlsx 文件:<select style="height: 27px;top: -2px;position: relative;" id="Luckyexcel-select-demo"><option value="">选择网络文件</option><option value="https://minio.cnbabylon.com/public/luckysheet/money-manager-2.xlsx">Money Manager.xlsx</option><option value="https://minio.cnbabylon.com/public/luckysheet/Activity%20costs%20tracker.xlsx">Activity costs tracker.xlsx</option><option value="https://minio.cnbabylon.com/public/luckysheet/House%20cleaning%20checklist.xlsx">House cleaning checklist.xlsx</option><option value="https://minio.cnbabylon.com/public/luckysheet/Student%20assignment%20planner.xlsx">Student assignment planner.xlsx</option><option value="https://minio.cnbabylon.com/public/luckysheet/Credit%20card%20tracker.xlsx">Credit card tracker.xlsx</option><option value="https://minio.cnbabylon.com/public/luckysheet/Blue%20timesheet.xlsx">Blue timesheet.xlsx</option><option value="https://minio.cnbabylon.com/public/luckysheet/Student%20calendar%20%28Mon%29.xlsx">Student calendar (Mon).xlsx</option><option value="https://minio.cnbabylon.com/public/luckysheet/Blue%20mileage%20and%20expense%20report.xlsx">Blue mileage and expense report.xlsx</option></select><a href="javascript:void(0)" id="Luckyexcel-downlod-file">下载 xlsx 文件</a><a href="javascript:void(0)" id="Luckyexcel-upload-file">上传到服务器</a></p><div id="luckysheet"style="margin:0px;padding:0px;position:absolute;width:100%;left: 0px;top: 50px;bottom: 0px;outline: none;"></div><!-- <script src="luckyexcel.umd.js"></script> --><script src="https://cdn.jsdelivr.net/npm/luckyexcel/dist/luckyexcel.umd.js"></script><!-- <script type="module">import l from './luckyexcel.js';console.info('=====',l)// window.onload = () => {//     let upload = document.getElementById("file");//     upload.addEventListener("change", function(evt){//         var files = evt.target.files;   //         importFile(files[0]);//     });// }</script> --><script>let fullName=''; // 正在编辑的Excel文件名,包含后缀名function demoHandler() {let upload = document.getElementById("Luckyexcel-demo-file");let selectADemo = document.getElementById("Luckyexcel-select-demo");let downlodDemo = document.getElementById("Luckyexcel-downlod-file");let uploadDemo = document.getElementById("Luckyexcel-upload-file");let mask = document.getElementById("lucky-mask-demo");if (upload) {window.onload = () => {upload.addEventListener("change", function (evt) {var files = evt.target.files;if (files == null || files.length == 0) {alert("No files wait for import");return;}let name = files[0].name;let suffixArr = name.split("."), suffix = suffixArr[suffixArr.length - 1];if (suffix != "xlsx") {alert("Currently only supports the import of xlsx files");return;}fullName=name;LuckyExcel.transformExcelToLucky(files[0], function (exportJson, luckysheetfile) {if (exportJson.sheets == null || exportJson.sheets.length == 0) {alert("Failed to read the content of the excel file, currently does not support xls files!");return;}window.luckysheet.destroy();window.luckysheet.create({container: 'luckysheet', //luckysheet is the container idshowinfobar: false,data: exportJson.sheets,title: '在线表格',userInfo: exportJson.info.name.creator,lang: 'zh'});});});selectADemo.addEventListener("change", function (evt) {var obj = selectADemo;var index = obj.selectedIndex;var value = obj.options[index].value;var name = obj.options[index].innerHTML;if (value == "") {return;}fullName=name;mask.style.display = "flex";LuckyExcel.transformExcelToLuckyByUrl(value, name, function (exportJson, luckysheetfile) {if (exportJson.sheets == null || exportJson.sheets.length == 0) {alert("Failed to read the content of the excel file, currently does not support xls files!");return;}console.log(exportJson, luckysheetfile);mask.style.display = "none";window.luckysheet.destroy();window.luckysheet.create({container: 'luckysheet', //luckysheet is the container idshowinfobar: false,data: exportJson.sheets,title: '在线表格',userInfo: exportJson.info.name.creator,lang: 'zh'});});});uploadDemo.addEventListener("click", function (evt) {uploadExcel(window.luckysheet.getAllSheets(), fullName)  // 上传到服务器});downlodDemo.addEventListener("click", function (evt) {exportExcelFront(window.luckysheet.getAllSheets(), fullName) // 下载Excel// var obj = selectADemo;// var index = obj.selectedIndex;// var value = obj.options[index].value;// if (value.length == 0) {//     alert("Please select a demo file");//     return;// }// var elemIF = document.getElementById("Lucky-download-frame");// if (elemIF == null) {//     elemIF = document.createElement("iframe");//     elemIF.style.display = "none";//     elemIF.id = "Lucky-download-frame";//     document.body.appendChild(elemIF);// }// elemIF.src = value;});}}}demoHandler();/*** 上传到服务器* @param luckysheet    -> luckysheet的所有sheet* @param name          -> 保存文件名(如:a.xlsx)* @param excelType     -> office/wps*/var uploadExcel = function(luckysheet, name, excelType) {// 1.创建工作簿,可以为工作簿添加属性const workbook = new ExcelJS.Workbook()// 2.创建表格,第二个参数可以配置创建什么样的工作表luckysheet.forEach(function (table) {// debuggerif (table.data.length === 0) return trueconst worksheet = workbook.addWorksheet(table.name)const merge = (table.config && table.config.merge) || {}        //合并单元格const borderInfo = (table.config && table.config.borderInfo) || {}      //边框const columnWidth = (table.config && table.config.columnlen) || {}    //列宽const rowHeight = (table.config && table.config.rowlen) || {}      //行高const frozen = table.frozen || {}       //冻结const rowhidden = (table.config && table.config.rowhidden) || {}    //行隐藏const colhidden = (table.config && table.config.colhidden) || {}    //列隐藏const filterSelect = table.filter_select || {}    //筛选const images = table.images || {}   //图片// console.log(table)const hide = table.hide;    //工作表 sheet 1隐藏if (hide === 1) {// 隐藏工作表worksheet.state = 'hidden';}setStyleAndValue(table.data, worksheet)setMerge(merge, worksheet)setBorder(borderInfo, worksheet)setImages(images, worksheet, workbook)setColumnWidth(columnWidth, worksheet)//行高设置50导出后在ms-excel中打开显示25,在wps-excel中打开显示50这个bug不会修复setRowHeight(rowHeight, worksheet, excelType)setFrozen(frozen, worksheet)setRowHidden(rowhidden, worksheet)setColHidden(colhidden, worksheet)setFilter(filterSelect, worksheet)return true})// 4.写入 bufferconst buffer = workbook.xlsx.writeBuffer().then(data => {const blob = new Blob([data], {type: 'application/vnd.ms-excel;charset=utf-8'})// 创建FormData对象const formData = new FormData();formData.append('file', blob, `${name}`);// 创建XMLHttpRequest对象const xhr = new XMLHttpRequest();// 配置请求xhr.open('POST', 'http://127.0.0.1:3000/upload', true);// 设置请求完成的回调函数xhr.onload = function () {if (xhr.status === 200) {alert('已上传成功!')console.log('Success:', xhr.responseText);} else {alert('上传失败!'+xhr.statusText)console.error('Error:', xhr.statusText);}};// 设置请求失败的回调函数xhr.onerror = function () {console.error('Network error occurred');};// 设置请求超时的回调函数(可选)xhr.ontimeout = function (e) {console.error('Request timed out');};// 设置请求超时时间(可选)xhr.timeout = 5000; // 5秒// 发送FormData对象xhr.send(formData);// 设置请求头(可选,某些浏览器可能不需要)xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');})return buffer}/*** 下载Excel* @param luckysheet    -> luckysheet的所有sheet* @param name          -> 保存文件名(如:a.xlsx)* @param excelType     -> office/wps*/var exportExcelFront = function(luckysheet, name, excelType) {// 1.创建工作簿,可以为工作簿添加属性const workbook = new ExcelJS.Workbook()// 2.创建表格,第二个参数可以配置创建什么样的工作表luckysheet.forEach(function (table) {// debuggerif (table.data.length === 0) return trueconst worksheet = workbook.addWorksheet(table.name)const merge = (table.config && table.config.merge) || {}        //合并单元格const borderInfo = (table.config && table.config.borderInfo) || {}      //边框const columnWidth = (table.config && table.config.columnlen) || {}    //列宽const rowHeight = (table.config && table.config.rowlen) || {}      //行高const frozen = table.frozen || {}       //冻结const rowhidden = (table.config && table.config.rowhidden) || {}    //行隐藏const colhidden = (table.config && table.config.colhidden) || {}    //列隐藏const filterSelect = table.filter_select || {}    //筛选const images = table.images || {}   //图片// console.log(table)const hide = table.hide;    //工作表 sheet 1隐藏if (hide === 1) {// 隐藏工作表worksheet.state = 'hidden';}setStyleAndValue(table.data, worksheet)setMerge(merge, worksheet)setBorder(borderInfo, worksheet)setImages(images, worksheet, workbook)setColumnWidth(columnWidth, worksheet)//行高设置50导出后在ms-excel中打开显示25,在wps-excel中打开显示50这个bug不会修复setRowHeight(rowHeight, worksheet, excelType)setFrozen(frozen, worksheet)setRowHidden(rowhidden, worksheet)setColHidden(colhidden, worksheet)setFilter(filterSelect, worksheet)return true})// 4.写入 bufferconst buffer = workbook.xlsx.writeBuffer().then(data => {const blob = new Blob([data], {type: 'application/vnd.ms-excel;charset=utf-8'})// 浏览器下载文件的示例代码console.log("导出成功!")saveAs(blob, `${name}`)})return buffer}/*** 列宽* @param columnWidth* @param worksheet*/var setColumnWidth = function (columnWidth, worksheet) {for (let key in columnWidth) {worksheet.getColumn(parseInt(key) + 1).width = columnWidth[key] / 7.5}}/*** 行高* @param rowHeight* @param worksheet* @param excelType*/var setRowHeight = function (rowHeight, worksheet, excelType) {//导出的文件用wps打开和用excel打开显示的行高大一倍if (excelType == "wps") {for (let key in rowHeight) {worksheet.getRow(parseInt(key) + 1).height = rowHeight[key] * 0.75}}if (excelType == "office" || excelType == undefined) {for (let key in rowHeight) {worksheet.getRow(parseInt(key) + 1).height = rowHeight[key] * 1.5}}}/*** 合并单元格* @param luckyMerge* @param worksheet*/var setMerge = function (luckyMerge = {}, worksheet) {const mergearr = Object.values(luckyMerge)mergearr.forEach(function (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)})}/*** 设置边框* @param luckyBorderInfo* @param worksheet*/var setBorder = function (luckyBorderInfo, worksheet) {if (!Array.isArray(luckyBorderInfo)) return//合并边框信息var mergeCellBorder = function (border1, border2) {if (undefined === border1 || Object.keys(border1).length === 0) return border2;return Object.assign({}, border1, border2)}// console.log('luckyBorderInfo', luckyBorderInfo)luckyBorderInfo.forEach(function (elem) {// 现在只兼容到borderType 为range的情况// console.log('ele', elem)if (elem.rangeType === 'range') {let border = borderConvert(elem.borderType, elem.style, elem.color)let rang = elem.range[0]let row = rang.rowlet column = rang.columnlet rowBegin = row[0]let rowEnd = row[1]let colBegin = column[0]let colEnd = column[1]//处理外边框的情况 没有直接对应的外边框 需要转换成上下左右if (border.all) {//全部边框let b = border.allfor (let i = row[0] + 1; i <= row[1] + 1; i++) {for (let y = column[0] + 1; y <= column[1] + 1; y++) {let border = {}border['top'] = b;border['bottom'] = b;border['left'] = b;border['right'] = b;worksheet.getCell(i, y).border = border// console.log(i, y, worksheet.getCell(i, y).border)}}} else if (border.top) {//上边框let b = border.toplet i = row[0] + 1;for (let y = column[0] + 1; y <= column[1] + 1; y++) {let border = {}border['top'] = b;worksheet.getCell(i, y).border = border// console.log(i, y, worksheet.getCell(i, y).border)}} else if (border.right) {//右边框let b = border.rightfor (let i = row[0] + 1; i <= row[1] + 1; i++) {let y = column[1] + 1;let border = {}border['right'] = b;worksheet.getCell(i, y).border = border// console.log(i, y, worksheet.getCell(i, y).border)}} else if (border.bottom) {//下边框let b = border.bottomlet i = row[1] + 1;for (let y = column[0] + 1; y <= column[1] + 1; y++) {let border = {}border['bottom'] = b;worksheet.getCell(i, y).border = border// console.log(i, y, worksheet.getCell(i, y).border)}} else if (border.left) {//左边框let b = border.leftfor (let i = row[0] + 1; i <= row[1] + 1; i++) {let y = column[0] + 1;let border = {}border['left'] = b;worksheet.getCell(i, y).border = border// console.log(i, y, worksheet.getCell(i, y).border)}} else if (border.outside) {//外边框let b = border.outsidefor (let i = row[0] + 1; i <= row[1] + 1; i++) {for (let y = column[0] + 1; y <= column[1] + 1; y++) {let border = {}if (i === rowBegin + 1) {border['top'] = b}if (i === rowEnd + 1) {border['bottom'] = b}if (y === colBegin + 1) {border['left'] = b}if (y === colEnd + 1) {border['right'] = b}let border1 = worksheet.getCell(i, y).borderworksheet.getCell(i, y).border = mergeCellBorder(border1, border)// console.log(i, y, worksheet.getCell(i, y).border)}}} else if (border.inside) {//内边框let b = border.insidefor (let i = row[0] + 1; i <= row[1] + 1; i++) {for (let y = column[0] + 1; y <= column[1] + 1; y++) {let border = {}if (i !== rowBegin + 1) {border['top'] = b}if (i !== rowEnd + 1) {border['bottom'] = b}if (y !== colBegin + 1) {border['left'] = b}if (y !== colEnd + 1) {border['right'] = b}let border1 = worksheet.getCell(i, y).borderworksheet.getCell(i, y).border = mergeCellBorder(border1, border)// console.log(i, y, worksheet.getCell(i, y).border)}}} else if (border.horizontal) {//内侧水平边框let b = border.horizontalfor (let i = row[0] + 1; i <= row[1] + 1; i++) {for (let y = column[0] + 1; y <= column[1] + 1; y++) {let border = {}if (i === rowBegin + 1) {border['bottom'] = b} else if (i === rowEnd + 1) {border['top'] = b} else {border['top'] = bborder['bottom'] = b}let border1 = worksheet.getCell(i, y).borderworksheet.getCell(i, y).border = mergeCellBorder(border1, border)// console.log(i, y, worksheet.getCell(i, y).border)}}} else if (border.vertical) {//内侧垂直边框let b = border.verticalfor (let i = row[0] + 1; i <= row[1] + 1; i++) {for (let y = column[0] + 1; y <= column[1] + 1; y++) {let border = {}if (y === colBegin + 1) {border['right'] = b} else if (y === colEnd + 1) {border['left'] = b} else {border['left'] = bborder['right'] = b}let border1 = worksheet.getCell(i, y).borderworksheet.getCell(i, y).border = mergeCellBorder(border1, border)// console.log(i, y, worksheet.getCell(i, y).border)}}} else if (border.none) {//当luckysheet边框为border-none的时候表示没有边框 则将对应的单元格border清空for (let i = row[0] + 1; i <= row[1] + 1; i++) {for (let y = column[0] + 1; y <= column[1] + 1; y++) {worksheet.getCell(i, y).border = {}// console.log(i, y, worksheet.getCell(i, y).border)}}}}if (elem.rangeType === 'cell') {// col_index: 2// row_index: 1// b: {//   color: '#d0d4e3'//   style: 1// }const { col_index, row_index } = elem.valueconst borderData = Object.assign({}, elem.value)delete borderData.col_indexdelete borderData.row_indexlet border = addborderToCell(borderData, row_index, col_index)let border1 = worksheet.getCell(row_index + 1, col_index + 1).border;worksheet.getCell(row_index + 1, col_index + 1).border = mergeCellBorder(border1, border)// console.log(row_index + 1, col_index + 1, worksheet.getCell(row_index + 1, col_index + 1).border)}})}/*** 设置带样式的值* @param cellArr* @param worksheet*/var setStyleAndValue = function (cellArr, worksheet) {if (!Array.isArray(cellArr)) returncellArr.forEach(function (row, rowid) {row.every(function (cell, columnid) {if (!cell) return truelet fill = fillConvert(cell.bg)let font = fontConvert(cell.ff,cell.fc,cell.bl,cell.it,cell.fs,cell.cl,cell.un)let 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) {// xls转为xlsx之后,内部存在不同的格式,都会进到富文本里,即值不存在与cell.v,而是存在于cell.ct.s之后let richText = [];let cts = cell.ct.sfor (let i = 0; i < cts.length; i++) {let rt = {text: cts[i].v,font: fontConvert(cts[i].ff, cts[i].fc, cts[i].bl, cts[i].it, cts[i].fs, cts[i].cl, cts[i].un)}richText.push(rt)}value = {richText: richText};} else {//设置值为数字格式if (cell.v !== undefined && cell.v !== '') {var v = +cell.v;if (isNaN(v)) v = cell.vvalue = v}}//  style 填入到_value中可以实现填充色let letter = createCellPos(columnid)let target = worksheet.getCell(letter + (rowid + 1))// console.log('1233', letter + (rowid + 1))for (const key in fill) {target.fill = fillbreak}target.font = fonttarget.alignment = alignmenttarget.value = valuetry {//设置单元格格式target.numFmt = cell.ct.fa;} catch (e) {console.warn(e)}return true})})}/*** 设置图片* @param images* @param worksheet* @param workbook*/var setImages = function (images, worksheet, workbook) {if (typeof images != "object") return;for (let key in images) {// console.log(images[key]);// "data:image/png;base64,iVBORw0KG..."// 通过 base64  将图像添加到工作簿const myBase64Image = images[key].src;//位置const tl = { col: images[key].default.left / 72, row: images[key].default.top / 19 }// 大小const ext = { width: images[key].default.width, height: images[key].default.height }const imageId = workbook.addImage({base64: myBase64Image,//extension: 'png',});worksheet.addImage(imageId, {tl: tl,ext: ext});}}/*** 冻结行列* @param frozen* @param worksheet*/var setFrozen = function (frozen = {}, worksheet) {switch (frozen.type) {// 冻结首行case 'row': {worksheet.views = [{ state: 'frozen', xSplit: 0, ySplit: 1 }];break}// 冻结首列case 'column': {worksheet.views = [{ state: 'frozen', xSplit: 1, ySplit: 0 }];break}// 冻结行列case 'both': {worksheet.views = [{ state: 'frozen', xSplit: 1, ySplit: 1 }];break}// 冻结行到选区case 'rangeRow': {let row = frozen.range.row_focus + 1worksheet.views = [{ state: 'frozen', xSplit: 0, ySplit: row }];break}// 冻结列到选区case 'rangeColumn': {let column = frozen.range.column_focus + 1worksheet.views = [{ state: 'frozen', xSplit: column, ySplit: 0 }];break}// 冻结行列到选区case 'rangeBoth': {let row = frozen.range.row_focus + 1let column = frozen.range.column_focus + 1worksheet.views = [{ state: 'frozen', xSplit: column, ySplit: row }];}}}/*** 行隐藏* @param rowhidden* @param worksheet*/var setRowHidden = function (rowhidden = {}, worksheet) {for (const key in rowhidden) {//如果当前行没有内容则隐藏不生效const row = worksheet.getRow(parseInt(key) + 1)row.hidden = true;}}/*** 列隐藏* @param colhidden* @param worksheet*/var setColHidden = function (colhidden = {}, worksheet) {for (const key in colhidden) {const column = worksheet.getColumn(parseInt(key) + 1)column.hidden = true;}}/*** 自动筛选器* @param filter* @param worksheet*/var setFilter = function (filter = {}, worksheet) {if (Object.keys(filter).length === 0) returnconst from = {row: filter.row[0] + 1,column: filter.column[0] + 1}const to = {row: filter.row[1] + 1,column: filter.column[1] + 1}worksheet.autoFilter = {from: from,to: to}}var fillConvert = function (bg) {if (!bg) {return {}}// const bgc = bg.replace('#', '')let fill = {type: 'pattern',pattern: 'solid',fgColor: { argb: bg.startsWith("#") ? bg.replace('#', '') : colorRGBtoHex(bg).replace("#", "") },}return fill;}var fontConvert = function (ff = 0,fc = '#000000',bl = 0,it = 0,fs = 10,cl = 0,ul = 0) {// luckysheet:ff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)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: function (num) {return num !== 0}}// 出现Bug,导入的时候ff为luckyToExcel的vallet font = {name: typeof ff === 'number' ? luckyToExcel[ff] : ff,family: 1,size: fs,color: { argb: fc.startsWith("#") ? fc.replace('#', '') : colorRGBtoHex(fc).replace("#", "") },bold: luckyToExcel.num2bl(bl),italic: luckyToExcel.num2bl(it),underline: luckyToExcel.num2bl(ul),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: 'middle'},horizontal: {0: 'center',1: 'left',2: 'right',default: 'center'},wrapText: {0: false,1: false,2: true,default: false},textRotation: {0: 0,1: 45,2: -45,3: 'vertical',4: 90,5: -90,default: 0}}let alignment = {vertical: luckyToExcel.vertical[vt],horizontal: luckyToExcel.horizontal[ht],wrapText: luckyToExcel.wrapText[tb],textRotation: luckyToExcel.textRotation[tr]}return alignment}var borderConvert = function (borderType, style = 1, color = '#000') {// 对应luckysheet的config中borderinfo的的参数if (!borderType) {return {}}const luckyToExcel = {type: {'border-all': 'all','border-top': 'top','border-right': 'right','border-bottom': 'bottom','border-left': 'left','border-outside': 'outside','border-inside': 'inside','border-horizontal': 'horizontal','border-vertical': 'vertical','border-none': 'none',},style: {0: 'none',1: 'thin',2: 'hair',3: 'dotted',4: 'dashDot', // 'Dashed',5: 'dashDot',6: 'dashDotDot',7: 'double',8: 'medium',9: 'mediumDashed',10: 'mediumDashDot',11: 'mediumDashDotDot',12: 'slantDashDot',13: 'thick'}}let border = {}border[luckyToExcel.type[borderType]] = {style: luckyToExcel.style[style],color: { argb: color.replace('#', '') }}return border}function addborderToCell(borders, row_index, col_index) {let border = {}const luckyExcel = {type: {l: 'left',r: 'right',b: 'bottom',t: 'top'},style: {0: 'none',1: 'thin',2: 'hair',3: 'dotted',4: 'dashDot', // 'Dashed',5: 'dashDot',6: 'dashDotDot',7: 'double',8: 'medium',9: 'mediumDashed',10: 'mediumDashDot',11: 'mediumDashDotDot',12: 'slantDashDot',13: 'thick'}}// console.log('borders', borders)for (const bor in borders) {// console.log(bor)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) {let ordA = 'A'.charCodeAt(0)let ordZ = 'Z'.charCodeAt(0)let len = ordZ - ordA + 1let s = ''while (n >= 0) {s = String.fromCharCode((n % len) + ordA) + sn = Math.floor(n / len) - 1}return s}//rgb(255,255,255)转16进制 #fffffffunction colorRGBtoHex(color) {color = color.replace("rgb", "").replace("(", "").replace(")", "")var rgb = color.split(',');var r = parseInt(rgb[0]);var g = parseInt(rgb[1]);var b = parseInt(rgb[2]);return "#" + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);}</script>
</body></html>

Node.js 接收前端上传文件的示例代码

首先,确保您已经安装了multer和express:

npm install multer express


然后,您可以使用以下代码来设置一个Express服务器,该服务器能够接收Blob格式的文件上传:

在项目一级目录,创建uploads文件夹和server.js

const express = require('express');
const multer = require('multer');
const app = express();// 配置存储选项
const storage = multer.diskStorage({destination: function (req, file, cb) {cb(null, 'uploads/'); // 保存的路径,确保这个目录存在},filename: function (req, file, cb) {cb(null, file.originalname); // 使用原始文件名作为保存的文件名}
});// 创建multer实例
const upload = multer({ storage: storage });// 设置允许跨域请求,如果需要的话
app.use((req, res, next) => {res.header('Access-Control-Allow-Origin', '*');res.header('Access-Control-Allow-Methods', 'GET, POST');next();
});// 定义上传路由
app.post('/upload', upload.single('file'), (req, res) => {// req.file 包含了上传文件的信息if (!req.file) {return res.status(400).send('No file uploaded');}// 文件上传成功res.send(`File uploaded successfully. ${req.file.filename}`);
});// 启动服务器
const port = 3000;
app.listen(port, () => {console.log(`Server running on port ${port}`);
});

启动服务

node server.js

参考内容:

1. Luckyexcel/README-zh.md

2.使用exceljs导出luckysheet表格

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/544244.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity的AssetBundle资源运行内存管理的再次深入思考

大家好&#xff0c;我是阿赵。   这篇文章我想写了很久&#xff0c;是关于Unity项目使用AssetBundle加载资源时的内存管理的。这篇文章不会分享代码&#xff0c;只是分享思路&#xff0c;思路不一定正确&#xff0c;欢迎讨论。   对于Unity引擎的资源内存管理&#xff0c;我…

sqllab第二十六关通关笔记

知识点&#xff1a; 空格替换 %09 %0a %0b %0c %0d %a0 (%2b)or替换&#xff1a;|| ||是不需要空格区分的and替换&#xff1a;&& &&同样不需要空格区分的双写绕过&#xff0c;但是绕过后需要和内容进行空格区分的&#xff0c;要不然不发挥作用&#xff1b;这关…

获取扇区航班数

1、Spark Streaming清洗服务&#xff0c;接收kafka中Topic为“task_ATC”中的数据&#xff0c;保存在MySQL中。 打开SpringBoot项目BigData-Etl-KongGuan 请认真阅读&#xff1a;在前面的“使用Spark清洗统计业务数据并保存到数据库中”任务阶段中应该已经完成了所有Topic的数…

Ubuntu22.04桌面远程时使用vi编辑配置文件乱码

Ubuntu22.04 Desktop 版安装后&#xff0c;使用vi本地和远程编辑文件时会出现部分字母打不出&#xff0c;方向键会打出字母C、D&#xff0c;删除键无法删除等问题。 编辑 vimrc.tiny 文件&#xff0c;vi /etc/vim/vimrc.tiny 1、将兼容模式改为不兼容模式&#xff0c;set com…

【LeetCode热题100】146. LRU 缓存(链表)

一.题目要求 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;则返回关键字的值&#xff0c…

Rust学习02:推荐一本入门书,免费的

都说Rust的学习曲线很陡峭&#xff0c;试过才知雀实不容易。 先说我的基础&#xff0c;非科班&#xff0c;自学Python&#xff0c;写过几个小程序。 我买书从来不扣扣嗖嗖的&#xff0c;所以先啃了几本Rust的入门书&#xff0c;包括&#xff1a; Tim McNamara的《Rust实战》&am…

瑞_Redis_短信登录(二)

文章目录 项目介绍1.1 项目准备1.2 基于Session实现登录流程1.2.1 发送短信验证码1.2.2 短信验证码登录、注册1.2.3 校验登录状态 1.3 实现发送短信验证码功能1.3.1 页面流程1.3.2 代码实现 1.41.51.6 &#x1f64a; 前言&#xff1a;本文章为瑞_系列专栏之《Redis》的实战篇的…

最后十几天!未备案小程序将会被清退

微信官方通知 2023年8月9日&#xff0c;微信公众平台发布了“关于开展微信小程序备案的通知”&#xff1a; 去年就已经在逐步推进备案了&#xff0c;新注册小程序必须备案才可以上架。若微信小程序已上架&#xff0c;须于2024年3月31日前完成备案&#xff0c;逾期未完成备案&a…

8:00面试,8:06就出来了,问的问题有点变态。。。

从小厂出来&#xff0c;没想到在另一家公司又寄了。 到这家公司开始上班&#xff0c;加班是每天必不可少的&#xff0c;看在钱给的比较多的份上&#xff0c;就不太计较了。没想到9月一纸通知&#xff0c;所有人不准加班&#xff0c;加班费不仅没有了&#xff0c;薪资还要降40%…

matlab采用PSO优化算法进行机器人线路规划

1、内容简介 略 63-可以交流、咨询、答疑 matlab采用PSO优化算法进行机器人线路规划 2、内容说明 避障&#xff0c;PSO算法&#xff0c;固定点优化&#xff0c;支持障碍物、优化点设置 matlab采用PSO优化算法进行机器人线路规划 3、仿真分析 4、参考论文 略

Vue.js+SpringBoot开发数字化社区网格管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、开发背景四、系统展示五、核心源码5.1 查询企事业单位5.2 查询流动人口5.3 查询精准扶贫5.4 查询案件5.5 查询人口 六、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBootMySQL的数字化社区网格管理系统&#xf…

C语言例:设 int x=100; 则表达式 x++>100?x+20:x+10 的值

代码如下&#xff1a; #include<stdio.h> int main(void) {int x100, y;y x>100?x20:x10;printf("表达式x>100?x20:x10 的值为&#xff1a;%d\n",y); //111printf("x %d\n",x); //101return 0; } //三目逻辑运算符&#xff0c;条件…