使用exceljs導出luckysheet表格 純前端 支持離線使用

一.技術

exceljs,luckysheet

二.實現

參考網上博文exceljs對導出lucksheet表格的實現,發現存在一些問題并給予修復:

1.字體顏色、字號,加粗等適配的問題.

2.單元格對齊方式不生效;

3.單元格邊框無法繪制;

4.單元格邊框顏色及線型錯亂;

5.單元格列寬處理;

6.合并單元格導出錯亂;

7.其他的一些BUG

三.注意事項

1、由于luckysheet在網頁端和excel分辨率無法保持完全一致,所以導出到excel中的時候,可能存在單元格大小與原表格不一致的情況,需要在setStyleAndValue中對單元格大小進行手動調整,具體可查看代碼注釋。后續也會逐漸進行自動適配。

2、目前僅支持表格,數據透視表的導出;不支持圖片,圖表的導出,后續有時間慢慢完善。

四.使用教程

1、安裝 exceljs、file-saver

使用以下命令通過 npm 安裝 exceljsfile-saver

npm install exceljs file-saver

2、引用導出Excel文件

安裝完成后把找到 exceljs.min.js 和?FileSaver.min.js 文件拷貝到自己的項目中,并添加引用

D:\project\ExcelJS-demo\node_modules\exceljs\dist\exceljs.min.js
D:\project\ExcelJS-demo\node_modules\file-saver\dist\FileSaver.min.js
<script type="text/javascript" src="luckysheet/exceljs/exceljs.min.js"></script>
<script type="text/javascript" src="luckysheet/exceljs/FileSaver.min.js"></script>

3、調用導出Excel函數

這個函數是我自己封裝的版本

在項目里新建一個js文件,名為:exportExcel.js (可自定義),把下面這段導出的代碼粘貼進去

// 導出 Luckysheet 內容為 Excel(ExcelJS)
async function exportLuckysheetToExcelByExcelJS() {//創建工作簿const workbook = new ExcelJS.Workbook();// 啟用樣式支持(關鍵配置)workbook.useStyles = true;// 拿到當前激活頁的配置對象const activeSheet = luckysheet.getSheet();const originalSheetIndex = activeSheet.order ?? 0;// 激活每個 sheet,確保數據初始化(特別是數據透視表)const sheets = luckysheet.getAllSheets();for (let i = 0; i < sheets.length; i++) {luckysheet.setSheetActive(i);//每切換一次表格,延遲1ms,為了讓表格數據能夠正常加載和渲染。await new Promise(resolve => setTimeout(resolve, 1));if (i == sheets.length - 1) {// 恢復原始激活的 sheetluckysheet.setSheetActive(originalSheetIndex);}}// 重新獲取激活后的所有工作表const initializedSheets = luckysheet.getAllSheets();initializedSheets.forEach(sheet => {const worksheet = workbook.addWorksheet(sheet.name);// 1. 填充數據與樣式sheet.data.forEach((row, rowIndex) => {row.forEach((cell, colIndex) => {if (!cell) return;const excelCell = worksheet.getCell(rowIndex + 1, colIndex + 1);// 值或公式excelCell.value = cell.f ? { formula: cell.f, result: cell.v } : cell.v;// 字體樣式(字號、顏色、加粗、斜體、下劃線、字體名)const fontSizePx = cell.fs !== undefined ? cell.fs : 10;const font = { size: fontSizePx };if (cell.fc) font.color = { argb: hexToARGB(cell.fc) };if (cell.bl === 1) font.bold = true;if (cell.cl === 1) font.italic = true;if (cell.ul === 1) font.underline = true;if (cell.ff) font.name = cell.ff;excelCell.font = font;// 背景色if (cell.bg) {excelCell.fill = {type: 'pattern',pattern: 'solid',fgColor: { argb: hexToARGB(cell.bg) }};}// 對齊方式const hAlignMap = { 0: 'center', 1: 'left', 2: 'right' };const vAlignMap = { 0: 'middle', 1: 'top', 2: 'bottom' };const alignment = {};if (cell.ht !== undefined) alignment.horizontal = hAlignMap[cell.ht];if (cell.vt !== undefined) alignment.vertical = vAlignMap[cell.vt];if (Object.keys(alignment).length > 0) excelCell.alignment = alignment;});});// 2. 合并單元格const mergedMap = new Set();Object.values(sheet.config?.merge || {}).forEach(merge => {const r1 = merge.r + 1, c1 = merge.c + 1;const r2 = merge.r + merge.rs, c2 = merge.c + merge.cs;const mergeKey = `${r1},${c1},${r2},${c2}`;if (mergedMap.has(mergeKey)) return;mergedMap.add(mergeKey);try {worksheet.mergeCells(r1, c1, r2, c2);} catch (e) {console.warn(`跳過已合并區域:${mergeKey}`, e);}});// 3. 邊框處理(透視表默認細邊框)if (!sheet.config?.borderInfo && sheet.isPivotTable) {const { maxRow, maxCol } = getUsedRange(sheet);sheet.config = sheet.config || {};sheet.config.borderInfo = [{rangeType: "range",borderType: "border-all",style: "1",color: "#000000",range: [{ row: [0, maxRow - 1], column: [0, maxCol - 1] }]}];}(sheet.config?.borderInfo || []).forEach(border => {const rawColor = border.color === '#000' ? '#000000' : border.color;const color = hexToARGB(rawColor || '#000000');const borderStyleMap = {"1": "thin", // 細線"2": "dashed",// 虛線"3": "dotted", // 點線"4": "thick",// 粗線"5": "thick",// 粗線"6": "dashed",// 虛線"7": "dotted", // 點線"8": "medium",// 中等"9": "dashed",// 虛線"10": "thick"// 粗線};const styleName = borderStyleMap[border.style] || 'thin';const style = { style: styleName, color: { argb: color } };(border.range || []).forEach(range => {const r1 = range.row[0], r2 = range.row[1];const c1 = range.column[0], c2 = range.column[1];for (let r = r1; r <= r2; r++) {for (let c = c1; c <= c2; c++) {const cell = worksheet.getCell(r + 1, c + 1);const oldBorder = cell.border || {};let newBorder = { ...oldBorder };switch (border.borderType) {case 'left': newBorder.left = style; break;case 'right': newBorder.right = style; break;case 'top': newBorder.top = style; break;case 'bottom': newBorder.bottom = style; break;case 'border-all':case 'all':newBorder = {top: style, bottom: style,left: style, right: style};break;}cell.border = newBorder;}}});});// 4. 列寬設置const colConfig = sheet.config?.columnlen || {};const colCount = sheet.data?.[0]?.length || 0;for (let c = 0; c < colCount; c++) {const excelCol = worksheet.getColumn(c + 1);const luckysheetWidth = colConfig[c];if (luckysheetWidth !== undefined) {excelCol.width = Math.round(luckysheetWidth / 7 * 100) / 100;} else {excelCol.width = 10;}}});// 5. 生成文件并下載const buffer = await workbook.xlsx.writeBuffer();saveAs(new Blob([buffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }),'onlieExcel.xlsx');
}// 轉換顏色為 ExcelJS ARGB 格式
function hexToARGB(hex) {if (!hex || !hex.startsWith('#')) return undefined;const rgb = hex.slice(1).toUpperCase();return 'FF' + rgb;
}// 獲取使用區域的最大行列
function getUsedRange(sheet) {let maxRow = 0;let maxCol = 0;sheet.data.forEach((row, rowIndex) => {if (row) {row.forEach((cell, colIndex) => {if (cell && cell.v !== undefined && cell.v !== null && cell.v !== '') {maxRow = Math.max(maxRow, rowIndex);maxCol = Math.max(maxCol, colIndex);}});}});return { maxRow: maxRow + 1, maxCol: maxCol + 1 };
}

在頁面里引用?exportExcel.js 文件

<script type="text/javascript" src="luckysheet/exceljs/exportExcel.js"></script>

調用?exportLuckysheetToExcelByExcelJS() 方法實現導出

<a href="javascript:exportLuckysheetToExcelByExcelJS()" id="btnExport">導出Xlsx</a>

歷時3天的勞動成果終于結束,收官,撒花 ??ヽ(°▽°)ノ?

五.源碼下載

luckysheet demo 完整代碼,包括以下功能:

1、Luckysheet 本地引入方式,已解決斷網報錯,字體圖標不顯示的問題

2、使用SheetJS實現導入到luckysheet中,純前端,支持離線使用

3、使用ExcelJS實現導出luckysheet表格,純前端,支持離線使用

點擊 下載demo


?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90341.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90341.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90341.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

從0到1學習c++ 命名空間

也是好久沒寫博客了&#xff0c;主播這半年一直在忙別的領域&#xff0c;在磁力驅動領域干了一年&#xff0c;最好發現自己對這個領域并不是很感興趣&#xff0c;做這個領域多半都是為了發文章&#xff0c;現在閑下來了&#xff0c;主播終于也是過上好日子了&#xff0c;主播又…

大模型提示詞漏洞攻防測試:技術分析與實踐指南

引言 隨著ChatGPT、Claude、Gemini等大型語言模型(LLMs)的廣泛應用&#xff0c;它們已經成為現代AI系統的核心組件&#xff0c;被整合到各種產品和服務中。這些模型通過提示。Prompts)與用戶進行交互&#xff0c;而提示詞作為人類與AI溝通的橋梁&#xff0c;其安全性變得尤為重…

Golang實現 - 實現只有表頭的 Excel 模板,并在指定列添加了下拉框功能。生成的 Excel 文件在打開時,指定列的單元格會顯示下拉選項

該版本完全兼容最新版 excelize 庫 (v2.7)&#xff0c;實現了只有表頭的 Excel 模板&#xff0c;并在指定列添加了下拉框功能。生成的 Excel 文件在打開時&#xff0c;指定列的單元格會顯示下拉選擇箭頭。代碼如下&#xff1a;package mainimport ("fmt""log&qu…

全連接隊列

監聽套接字使用socket接口創建一個套接字&#xff0c;然后bind給套接字綁定地址&#xff0c;最后listen將套接字設置為監聽套接字。監聽套接字以前理解是三元組標識&#xff0c;后面看了netstat&#xff0c;覺得應該是五元組&#xff0c;只不過它這個五元組是{協議&#xff0c;…

JavaWeb-JSP

JSP JSP就是模板引擎 Template&#xff0c;因為看到的jsp是模板不變的&#xff0c;如果想讓頁面發生改變&#xff0c;就是自己添加java代碼改變頁面。有Java代碼&#xff0c;Tomcat服務器就會對jsp模板進行解析&#xff0c;解析完之后就是Servlet&#xff08;java類&#xff09…

大模型中常說的Token到底是什么?和Cookie和Session有什么區別?一文講清

什么是Token&#xff08;令牌&#xff09;Acesss Token是訪問資源接口&#xff08;API&#xff09;時所需要的資源憑證。簡單token的組成&#xff1a;uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign&#xff08;簽名&#xff0c;token的前幾位以哈希算法壓縮成的一定長…

RAGFlow:檢索增強生成技術的高效實現與深度探索

在當今信息爆炸的時代&#xff0c;如何從海量的數據中快速、準確地獲取并利用有價值的信息&#xff0c;成為了眾多領域面臨的關鍵挑戰。檢索增強生成&#xff08;Retrieval-Augmented Generation, RAG&#xff09;技術應運而生&#xff0c;它將信息檢索與大型語言模型&#xff…

【軌物洞見】光伏逆變器數據:分布式電站價值回歸的“第一塊多米諾骨牌”

1. 逆變器&#xff1a;光伏電站的核心“數據心臟” 逆變器是將光伏組件產生的直流電轉換為交流電的關鍵設備&#xff0c;其性能直接影響著整個電站的效率與穩定性。對其電壓、電流、功率參數以及故障告警信息進行遠程數據采集&#xff0c;是實現精細化運維和預測性維護的起點。…

如何在 npm 上發布 Element Plus 二次封裝組件

在一次開發中&#xff0c;小李接到一個重要的任務&#xff1a;將 Element Plus 中的時間組件根據團隊的獨特需求進行二次封裝。他靈機一動&#xff0c;決定將這個自定義組件打包成一個 npm 包&#xff0c;以便團隊的其他小伙伴們可以快速、方便地使用。接下來&#xff0c;讓我們…

vue2使用v-viewer圖片預覽:打開頁面自動預覽,禁止關閉預覽,解決在微信瀏覽器的頁面點擊事件老是觸發預覽初始化的問題

1、安裝&#xff1a; npm install v-viewer viewerjs2、在 main.js 中全局注冊&#xff1a; import Viewer from v-viewer; import viewerjs/dist/viewer.css; Vue.use(Viewer ); //配置項&#xff08;可選&#xff0c;根據需求調整&#xff09; // Vue.use(Viewer, { // d…

開源 Arkts 鴻蒙應用 開發(八)多媒體--相冊和相機

文章的目的為了記錄使用Arkts 進行Harmony app 開發學習的經歷。本職為嵌入式軟件開發&#xff0c;公司安排開發app&#xff0c;臨時學習&#xff0c;完成app的開發。開發流程和要點有些記憶模糊&#xff0c;趕緊記錄&#xff0c;防止忘記。 相關鏈接&#xff1a; 開源 Arkts …

無線通信資源分配相關算法

1.Maximum Clique First (MCF)是一種啟發式圖著色算法&#xff08;heuristic graph coloring algorithm&#xff09;&#xff0c;它的核心思想是&#xff1a;優先為圖中最大團&#xff08;maximum clique&#xff09;中的頂點分配不同的顏色&#xff0c;然后再依次為其他頂點上…

Kafka監控體系搭建:基于Prometheus+JMX+Grafana的全方位性能觀測方案

為什么需要Kafka監控監控架構概述步驟一&#xff1a;部署JMX Exporter 1.1 下載JMX Agent1.2 創建指標暴露配置 步驟二&#xff1a;配置Kafka集成JMX 2.1 啟動參數配置2.2 驗證指標暴露 步驟三&#xff1a;配置Prometheus采集 3.1 修改Prometheus配置3.2 驗證數據采集 步驟四&a…

stack 和 queue

目錄 一、stack 1.1 stack 的介紹 1.2 stack的使用 1&#xff09;最小棧 2&#xff09;棧的彈出壓入序列 3&#xff09;逆波蘭表達式求值 1.3 stack 的模擬使用 二、queue 2.1 queue的介紹 2.2 queue的使用 2.3 queue的模擬使用 三、容器適配器 3.1 什么是容器適配…

sqlsuger 子表獲取主表中的一個字段的寫法

在使用 SQL 語言進行數據庫操作時&#xff0c;如果你想要從子表獲取數據&#xff0c;同時關聯到主表中的一個字段&#xff0c;通常我們會使用 SQL 的 JOIN 語句。JOIN 語句允許你通過一個或多個共同的字段將兩個或多個表連接起來。這里我將展示幾種常見的 JOIN 類型&#xff08…

Docker配置Gitlab-runner實現自動化容器化部署前端項目

疊甲前言 本文僅作為個人學習GitLab的CI/CD功能記錄&#xff0c;不適合作為專業性指導&#xff0c;如有紕漏&#xff0c;煩請君指正。 云主機注冊Gitlab Runner 自動化構建部署的弊端 在前一文中&#xff0c;我們在Linux云主機上注冊了Gitlab-runner, 每次在gitlab流水線上發…

MySQL介紹和MySQL包安裝

文章目錄MySQL介紹和安裝1.MySQL介紹1.1 MySQL 的定義1.2 MySQL 的特點1.3 MySQL 的應用領域1.4 MySQL 的存儲引擎1.5 MySQL 的架構1.6 MySQL 的優勢和局限性1.7 MySQL 的未來發展趨勢2.MySQL安裝2.1 主機初始化2.1.1 設置網卡名2.1.2 設置ip地址2.1.3 配置鏡像源2.1.4 關閉防火…

J2EE模式---視圖助手模式

視圖助手模式基礎概念視圖助手模式&#xff08;View Helper Pattern&#xff09;是一種結構型設計模式&#xff0c;其核心思想是將視圖層中復雜的邏輯提取到獨立的助手類中&#xff0c;使視圖代碼更加簡潔、易于維護。視圖助手通常提供一系列工具方法&#xff0c;用于處理格式化…

開源的語音合成大模型-Cosyvoice使用介紹

1 模型概覽 CosyVoice 是由阿里巴巴達摩院通義實驗室開發的新一代生成式語音合成大模型系列&#xff0c;其核心目標是通過大模型技術深度融合文本理解與語音生成&#xff0c;實現高度擬人化的語音合成體驗。該系列包含初代 CosyVoice 及其升級版 CosyVoice 2.0&#xff0c;兩者…

深度學習·CLIP

CLIP 數據大小 4億個文本-圖像對&#xff0c;而且是高質量的 預訓練方法 Text encoder“The text sequence is bracketed with [SOS] and [EOS] tokens and the activations of the highest layer of the transformer at the [EOS] token are used as the feature representati…