当前位置: 首页 > news >正文

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表格

相关文章:

  • 【算法训练营】最近点对,纸牌,青蛙(Python实现)
  • 【Stable Diffusion】入门-04:不同模型分类+代表作品+常用下载网站+使用技巧
  • Maven 之 配置文件pom
  • stm32f103c8t6学习笔记(学习B站up江科大自化协)-USART串口-软件部分
  • IBM DataStage服务的启动和停止
  • k8s编排系统
  • SQLiteC/C++接口详细介绍之sqlite3类(十三)
  • 用云服务器构建gpt和stable-diffusion大模型
  • 3D Occupancy 预测冠军方案:FB-OCC
  • Oracle SQL优化基本概念:直方图
  • 计算机网络——物理层(数据交换方式)
  • Task-balanced distillation for object detection用于
  • 编译原理-实现识别标识符的词法分析器——沐雨先生
  • ARM 汇编指令:(七) STM/LDM多寄存器加载/多存储指令
  • Python的Selenium库中的模块、类和异常的汇总
  • 【vuex入门系列02】mutation接收单个参数和多个参数
  • 【知识碎片】第三方登录弹窗效果
  • android 一些 utils
  • classpath对获取配置文件的影响
  • Consul Config 使用Git做版本控制的实现
  • Create React App 使用
  • create-react-app项目添加less配置
  • download使用浅析
  • Java新版本的开发已正式进入轨道,版本号18.3
  • Linux快速复制或删除大量小文件
  • Quartz初级教程
  • ReactNative开发常用的三方模块
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 力扣(LeetCode)56
  • 马上搞懂 GeoJSON
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 什么软件可以提取视频中的音频制作成手机铃声
  • 问题之ssh中Host key verification failed的解决
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 一些关于Rust在2019年的思考
  • 与 ConTeXt MkIV 官方文档的接驳
  • 源码安装memcached和php memcache扩展
  • ​LeetCode解法汇总518. 零钱兑换 II
  • ###51单片机学习(2)-----如何通过C语言运用延时函数设计LED流水灯
  • #HarmonyOS:软件安装window和mac预览Hello World
  • (1)虚拟机的安装与使用,linux系统安装
  • (C++)八皇后问题
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (附源码)计算机毕业设计高校学生选课系统
  • (删)Java线程同步实现一:synchronzied和wait()/notify()
  • (四)Controller接口控制器详解(三)
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • **CI中自动类加载的用法总结
  • .NET delegate 委托 、 Event 事件,接口回调
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • .NET开发人员必知的八个网站
  • .NET框架设计—常被忽视的C#设计技巧
  • @Repository 注解
  • []新浪博客如何插入代码(其他博客应该也可以)
  • [2023年]-hadoop面试真题(一)