使用exceljs將excel文件轉化為html預覽最佳實踐(完整源碼)

前言

在企業應用中,我們時常會遇到需要上傳并展示 Excel 文件的需求,以實現文件內容的在線預覽。經過一番探索與嘗試,筆者最終借助 exceljs 這一庫成功實現了該功能。本文將以 Vue 3 為例,演示如何實現該功能,代碼示例可直接復制運行,希望能為大家在處理類似問題時提供新的思路和解決方案。

技術難點

基礎單元格和合并單元格的混合處理

文字樣式和背景樣式的讀取映射

富文本內容格式的處理

excel文件展示

實際實現預覽效果

核心代碼

exceljs提供了合并區域的數據,我們只需要根據合并區域去判斷什么時候該合并,就能很好的實現基礎單元格和合并單元格的混合繪制

  for (let merge of merges) {const [start, end] = merge.split(":");const startCell = worksheet.getCell(start);const endCell = worksheet.getCell(end);const startRow = startCell.row,startCol = startCell.col;const endRow = endCell.row,endCol = endCell.col;if (startRow === rowIndex && startCol === colIndex) {rowspan = endRow - startRow + 1;colspan = endCol - startCol + 1;isMerged = true;let styles = handleStyles(cell);allHtml += `<td rowspan="${rowspan}" colspan="${colspan}" style="${styles}">${handleValue(startCell.value)}</td>`;break;}if (rowIndex >= startRow &&rowIndex <= endRow &&colIndex >= startCol &&colIndex <= endCol) {isMerged = true;break;}}

完整源碼

<template><div><el-uploadaction="":auto-upload="false":show-file-list="true":on-change="handleFileUpload"accept=".xlsx,.xls"><el-button type="primary"> 上傳 Excel </el-button></el-upload><!-- 渲染 Excel 生成的 HTML 表格 --><div v-html="tableHtml" /></div>
</template><script setup>
import { ref } from "vue";
import * as ExcelJS from "exceljs";const tableHtml = ref(""); // 存儲 HTML 表格內容
const themeColors = {0: "#FFFFFF", // 白色 √1: "#000000", // 黑色 √2: "#C9CDD1", // 灰色 √3: "#4874CB", // 藍色 √4: "#D9E1F4", // 淺藍 √5: "#F9CBAA", // 橙色 √6: "#F2BA02", // 淺橙 √7: "#00FF00", // 淺綠 √8: "#30C0B4", // 青色 √9: "#E54C5E", // 紅色 √10: "#FFC7CE", // 淺紅11: "#7030A0", // 紫色
};// 獲取單元格顏色
const getCellColor = (cell) => {if (cell.fill && cell.fill.fgColor) {if (cell.fill.fgColor.argb) {return `#${cell.fill.fgColor.argb.substring(2)}`; // ARGB 轉 RGB}if (cell.fill.fgColor.theme !== undefined) {return themeColors[cell.fill.fgColor.theme] || "#FFFFFF"; // 主題色轉換}}return ""; // 無顏色
};
// 獲取單元格字體顏色
const getCellFontColor = (cell) => {if (cell.font && cell.font.color && cell.font.color.argb) {return `#${cell.font.color.argb.substring(2)}`; // ARGB 轉 RGB}if (cell.font && cell.font.color && cell.font.color.theme) {return themeColors[cell.font.color.theme] || "#000"; // 主題色轉換}return "#000"; // 默認黑色
};
const handleStyles = (cell) => {let styles = [];// 讀取字體顏色styles.push(`color: ${getCellFontColor(cell)}`);// 讀取背景色styles.push(`background-color: ${getCellColor(cell)}`);// 加粗if (cell.font && cell.font.bold) {styles.push("font-weight: bold");}// 文字對齊if (cell.alignment) {if (cell.alignment.horizontal) {styles.push(`text-align: ${cell.alignment.horizontal}`);}if (cell.alignment.vertical) {styles.push(`vertical-align: ${cell.alignment.vertical}`);}}return styles.join("; ");
};// 處理上傳的 Excel 文件
const handleFileUpload = async (file) => {const excelData = await readExcel(file.raw);tableHtml.value = excelData; // 更新 HTML 表格內容
};
// 處理常規單元格內容
const handleValueSimple = (value) => {if (value && typeof value === "object" && value.richText) {const valueStr = value.richText.reduce((acc, curr) => {let colorValue = "";if (curr.font && curr.font.color && curr.font.color.theme) {colorValue = getCellFontColor(curr) || `#000`;}if (curr.font && curr.font.color && curr.font.color.argb) {colorValue = `#${curr.font.color.argb.substring(2)}`;} else {colorValue = `#000`;}return acc + `<span style="color:${colorValue}">${curr.text}</span>`;}, "");return valueStr;}return value ? value : "";
};
// 處理合并單元格內容
const handleValue = (value) => {if (value && typeof value === "object" && value.richText) {const valueArr = value.richText.reduce((acc, curr) => {let colorValue = "";if (curr.font && curr.font.color && curr.font.color.argb) {colorValue = `#${curr.font.color.argb.substring(2)}`;} else {colorValue = `#000`;}const newData = curr.text.split(/\r/).map((item) => `<p style="color:${colorValue}">${item}</p>`);return acc.concat(newData);}, []);return valueArr.join("").replace(/\n/g, "<br />");}return value ? value : "";
};let worksheetIds = [];
// 讀取 Excel 并轉換成 HTML
const readExcel = async (file) => {const workbook = new ExcelJS.Workbook();const arrayBuffer = await file.arrayBuffer();const { worksheets } = await workbook.xlsx.load(arrayBuffer);worksheetIds = worksheets.map((v) => v.id); // 獲取工作表 ID集合let allHtml = "";workbook.eachSheet(function (worksheet, sheetId) {// 處理合并單元格const merges = worksheet?.model?.merges || [];const currentSheetIndex = worksheetIds.indexOf(sheetId); // 獲取當前工作表的索引allHtml +='<table border="1" style="border-collapse: collapse;width:100%;margin-bottom: 20px;">';worksheet.eachRow((row, rowIndex) => {allHtml += "<tr>";row.eachCell((cell, colIndex) => {let cellValue = cell.value || "";// 處理合并單元格let rowspan = 1,colspan = 1;let isMerged = false;for (let merge of merges) {const [start, end] = merge.split(":");const startCell = worksheet.getCell(start);const endCell = worksheet.getCell(end);const startRow = startCell.row,startCol = startCell.col;const endRow = endCell.row,endCol = endCell.col;if (startRow === rowIndex && startCol === colIndex) {rowspan = endRow - startRow + 1;colspan = endCol - startCol + 1;isMerged = true;let styles = handleStyles(cell);allHtml += `<td rowspan="${rowspan}" colspan="${colspan}" style="${styles}">${handleValue(startCell.value)}</td>`;break;}if (rowIndex >= startRow &&rowIndex <= endRow &&colIndex >= startCol &&colIndex <= endCol) {isMerged = true;break;}}if (!isMerged) {let styles = handleStyles(cell);// 生成 HTML 單元格allHtml += `<td ${rowspan > 1 ? `rowspan="${rowspan}"` : ""} ${colspan > 1 ? `colspan="${colspan}"` : ""} style="${styles}">${handleValueSimple(cellValue)}</td>`;}});allHtml += "</tr>";});allHtml += "</table>";});return allHtml;
};
</script>

拓展

exceljs這個庫的作用是啥?

ExcelJS 是一個功能強大的庫,用于讀取、操作和寫入 Excel 文件(.xlsx 和 .csv 格式)。它允許開發者通過編程方式處理 Excel 文檔,包括創建新工作簿、添加數據、格式化單元格、插入圖表等。這個庫可以在服務器端(如 Node.js 環境)或客戶端(如在瀏覽器中使用 Webpack 或 Rollup 等工具打包的 JavaScript 應用程序)使用。

主要特性

  • 創建工作簿和工作表:可以輕松地創建新的 Excel 文件或修改已有的文件。
  • 豐富的樣式支持:支持字體、顏色、邊框、對齊方式等多種樣式設置。
  • 數據處理:支持從各種數據源導入數據,并能將數據導出為 Excel 文件。
  • 公式和計算:可以添加公式到單元格,并支持基本的 Excel 計算。
  • 圖表支持:能夠在 Excel 文件中創建圖表。
  • 圖片和繪圖:支持向 Excel 文件中添加圖片和繪制圖形。

使用場景

ExcelJS 廣泛應用于需要與 Excel 文件進行交互的應用程序開發中,比如:

  • 數據報告生成
  • 數據導入/導出功能實現
  • 在線 Excel 編輯器

示例代碼片段

這里是一個簡單的示例,展示如何使用 ExcelJS 創建一個新的工作簿并添加一些數據:

const ExcelJS = require('exceljs');// 創建一個新的工作簿
let workbook = new ExcelJS.Workbook();
let worksheet = workbook.addWorksheet('測試工作表');// 添加一行數據
worksheet.addRow(['姓名', '年齡', '郵箱']);
worksheet.addRow(['張三', 28, 'zhangsan@example.com']);
worksheet.addRow(['李四', 23, 'lisi@example.com']);// 保存工作簿到文件
workbook.xlsx.writeFile('example.xlsx').then(() => {console.log('文件保存成功');});

?這個例子展示了如何創建一個新的 Excel 文件,并向其中添加一些簡單數據。ExcelJS 的靈活性和強大功能使其成為處理 Excel 文件的一個優秀選擇。

npm上的puppeteer庫是做什么的?

npm 上的?puppeteer?是一個用于自動化控制 Chrome/Chromium 瀏覽器的 Node.js 庫,由 Google 團隊開發。它通過提供高級 API,允許你以編程方式模擬用戶在瀏覽器中的操作,適用于多種場景:

核心功能

  1. 無頭瀏覽器控制
    可啟動?Headless 模式(無界面)或完整瀏覽器,執行自動化任務(如點擊、輸入、導航等)。

  2. 動態內容抓取
    適用于爬取 JavaScript 渲染的頁面(如 React/Vue 單頁應用),傳統爬蟲工具難以直接獲取動態內容。

  3. 生成截圖與 PDF
    精確截取網頁全屏、指定區域,或將頁面導出為 PDF(保留樣式)。

  4. 自動化測試
    模擬用戶操作,測試網頁功能(如表單提交、UI 交互),生成測試報告。

  5. 性能分析
    監控頁面加載速度、資源請求,優化性能。

?典型使用場景

  • 數據抓取:爬取電商價格、社交媒體內容等動態加載的數據。

  • 自動化操作:自動填寫表單、批量下載文件、定時簽到等。

  • 預渲染:為 SEO 生成靜態化內容,解決 SPA 首屏加載問題。

  • 生成報告:將數據可視化頁面導出為 PDF 或圖片存檔。

?基礎示例

const puppeteer = require('puppeteer');(async () => {// 啟動瀏覽器(默認 Headless 模式)const browser = await puppeteer.launch();const page = await browser.newPage();// 導航到目標頁面await page.goto('https://example.com');// 截圖并保存await page.screenshot({ path: 'example.png' });// 關閉瀏覽器await browser.close();
})();

安裝與依賴

?通過 npm 安裝(會自動下載匹配的 Chromium):

npm install puppeteer

優勢

?

  • 直接操控瀏覽器:行為更接近真實用戶,繞過反爬蟲機制(需合理使用)。

  • 功能全面:支持網絡請求攔截、Cookie 管理、模擬設備(如手機/平板)等。

  • 社區活躍:豐富的文檔和第三方工具(如?puppeteer-cluster?多任務優化)。

若你需要處理復雜的網頁交互或動態內容,Puppeteer 是一個高效且靈活的選擇。

vue中為什么切換動態組件需要使用shallowRef ?

在 Vue 3 中,使用?shallowRef?來管理動態組件的切換,主要是出于性能優化和避免不必要的深度響應式追蹤的考慮。以下是詳細解釋:

1. ref vs shallowRef 的核心區別

會對其包裹的值進行深度響應式轉換(遞歸將對象屬性轉為響應式)。

僅對值的引用變化進行響應式追蹤,不會深度遞歸轉換內部屬性。

2.?動態組件的場景分析

當使用?<component :is="currentComponent">?切換組件時:

  • 組件對象本身是穩定的
    動態組件的核心操作是替換整個組件對象(如?currentComponent.value = NewComponent),而不是修改組件對象的內部屬性。
  • 組件對象可能很大
    一個組件對象(如導入的 Vue 組件)通常包含大量屬性(如?props、methods、生命周期等),如果使用?ref?深度響應式化,會帶來額外性能開銷。
  • 深度響應式可能導致問題
    某些組件屬性(如函數方法)被 Vue 代理后可能產生副作用(如破壞函數內部?this?綁定,或與第三方庫預期結構沖突)。

3.?為什么?shallowRef?更合適?

  • 性能優化
    避免深度遍歷組件對象的所有屬性,減少不必要的響應式代理。
  • 符合實際需求
    動態組件切換只需要響應組件引用的變化(整體替換),無需關心組件內部屬性的變化。
  • 規避潛在問題
    防止 Vue 對組件對象內部屬性(如方法、生命周期鉤子)的深度代理導致意外行為。

4.?示例對比

// 使用 ref(不推薦)import { ref } from 'vue';import HeavyComponent from './HeavyComponent.vue';const currentComponent = ref(HeavyComponent);// Vue 會深度代理 HeavyComponent 的所有屬性,但實際只需要引用變化觸發更新// 使用 shallowRef(推薦)import { shallowRef } from 'vue';const currentComponent = shallowRef(HeavyComponent);// 僅追蹤 currentComponent.value 的引用變化,高效且安全

5.?官方建議

Vue 官方文檔在動態組件示例中直接使用普通變量(非響應式),但在需要響應式時建議使用?shallowRef,明確表示:

“如果你確實需要響應性,可以使用?shallowRef。”

?在動態組件切換場景中,shallowRef?通過避免深度響應式轉換,在保證功能正確性的同時,提升了性能并規避了潛在問題。這正是它與?ref?的核心區別所在。

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

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

相關文章

PMP-第十二章 項目采購管理

項目采購管理核心概念 項目采購管理包括從項目團隊外部采購或獲取所需產品、服務或成果的各個過程項目組織既可以是買方&#xff08;甲方&#xff09; &#xff0c;也可以是賣方&#xff08;乙 方&#xff09;項目采購管理過程圍繞協議來進行&#xff0c;協議是買賣雙方之間具…

maven和npm區別是什么

這是一個很容易搞糊涂新手的問題&#xff0c;反正我剛開始從課堂的知識轉向項目網站開發時&#xff0c;被這些問題弄得暈頭轉向&#xff0c;摸不著頭腦&#xff0c;學的糊里糊涂&#xff0c;所以&#xff0c;寫了這么久代碼&#xff0c;也總結一下&#xff0c;為后來者傳授下經…

Leetcode76覆蓋最小子串

覆蓋最小子串 代碼來自b站左程云 class Solution {public String minWindow(String str, String tar) {char[] s str.toCharArray();char[] t tar.toCharArray();int[] cnt new int[256];for (char cha : t) { cnt[cha]--;}int len Integer.MAX_VALUE;int debt t.length…

Linux du 命令終極指南:從基礎到精通

文章目錄 Linux du 命令終極指南&#xff1a;從基礎到精通du 命令簡介常用參數詳解常見用法示例查看當前目錄總大小查看當前目錄及其子目錄占用空間只顯示當前目錄總占用空間查看目錄下每個文件和子目錄的大小查看某目錄深度為 1 的大小分布查看某目錄并排除日志文件查看多個目…

sychronized原理(嚼碎了喂版)

先說一下心得吧&#xff0c;我們知道硬軟不分家&#xff0c;在學習底層原理的時候我們不需要死扣到底&#xff0c;沒必要把硬件方面全吃透&#xff0c;點到為止&#xff0c;學到能夠幫助理解代碼即可&#xff0c;我們的目標是寫出高性能的代碼&#xff0c;而不是創造出硬軟一體…

Ngrok 配置:實現 Uniapp 前后端項目內網穿透

文章目錄 一、下載并安裝 ngrok二、配置 ngrok Authtoken三、啟動本地 uniapp 項目四、使用 ngrok 暴露本地服務五、通過公網 URL 訪問項目六、后端API項目的穿透問題排查 (uni-app 后端 API 示例)交互流程圖示 七、ngrok Web 界面 (本地監控)八、停止 ngrok總結 ngrok 是一款…

k8s灰度發布

基于 Traefik 的加權灰度發布-騰訊云開發者社區-騰訊云 Traefik | Traefik | v1.7 Releases traefik/traefik GitHub 從上面連接下載后上傳到harbor虛擬機 vagrant upload /C/Users/HP280/Downloads/traefik 下載配置文件 wget -c http://raw.githubusercontent.com/conta…

win10-django項目與mysql的基本增刪改查

以下都是在win10系統下&#xff0c;django項目的orm框架對本地mysql的表的操作 models.py----->即表對應的類所在的位置 在表里新增數據 1.引入表對應的在models.py中的類class 2.在views.py中使用函數&#xff1a;類名.objects.create(字段名值,字段名"值"。。。…

`ParameterizedType` 和 `TypeVariable` 的區別

在 Java 的泛型系統中&#xff0c;ParameterizedType 和 TypeVariable 是兩個不同的類型表示&#xff0c;它們都屬于 java.lang.reflect.Type 接口的子接口。兩者都在反射&#xff08;Reflection&#xff09;中用于描述泛型信息&#xff0c;但用途和含義不同。 &#x1f31f; 一…

PR-2021

推薦深藍學院的《深度神經網絡加速&#xff1a;cuDNN 與 TensorRT》&#xff0c;課程面向就業&#xff0c;細致講解CUDA運算的理論支撐與實踐&#xff0c;學完可以系統化掌握CUDA基礎編程知識以及TensorRT實戰&#xff0c;并且能夠利用GPU開發高性能、高并發的軟件系統&#xf…

unity使用ZXing.Net生成二維碼

下載鏈接 https://github.com/micjahn/ZXing.Net 放到Plugins下即可使用

Ubuntu 編譯SRS和ZLMediaKit用于視頻推拉流

SRS實現視頻的rtmp webrtc推流 ZLMediaKit編譯生成MediaServer實現rtsp推流 SRS指定某個固定網卡&#xff0c;修改程序后重新編譯 打開SRS-4.0.0/trunk/src/app/srs_app_rtc_server.cpp&#xff0c;在 232 行后面添加&#xff1a; ZLMediaKit編譯后文件存放在ZLMediakit/rele…

如何備考GRE?

1.引言 GRE和雅思不太相同&#xff0c;首先GRE是美國人的考試&#xff0c;思維方式和很多細節和英系雅思不一樣。所以底層邏輯上我覺得有點區別。 難度方面&#xff0c;我感覺GRE不容易考低分&#xff0c;但考高分較難。雅思就不一樣了不僅上限難突破&#xff0c;下限還容易6…

uniapp|商品列表加入購物車實現拋物線動畫效果、上下左右拋入、多端兼容(H5、APP、微信小程序)

以uniapp框架為基礎,詳細解析商品列表加入購物車拋物線動畫的實現方案。通過動態獲取商品點擊位置與購物車坐標,結合CSS過渡動畫模擬拋物線軌跡,實現從商品圖到購物車圖標的動態效果。 目錄 核心實現原理坐標動態計算拋物線軌跡模擬?動畫元素控制代碼實現詳解模板層設計腳本…

React中使用openLayer畫地圖

OpenLayers&#xff08;簡稱ol&#xff09;是一個?開源的WebGIS前端開發庫?&#xff0c;基于JavaScript實現&#xff0c;主要用于在網頁中嵌入動態二維地圖。 官方網站&#xff1a; https://openlayers.org 中文官網&#xff1a; https://openlayers.vip 大家可以去參考學習…

WHAT - 緩存命中 Cache Hit 和緩存未命中 Cache Miss

文章目錄 一、什么是緩存命中&#xff1f;二、前端開發要知道哪些緩存機制&#xff08;以及命中條件&#xff09;&#xff1f;1. 瀏覽器緩存&#xff08;主要針對靜態資源&#xff09;常見的緩存位置關鍵 HTTP 頭字段&#xff08;決定命中與否&#xff09; 2. 前端應用層緩存&a…

10 個可靠的 Android 文件傳輸應用程序

Android 文件傳輸是 Android 用戶的常見需求。我們經常需要將文件從一臺 Android 設備傳輸到 PC 或 Mac。但我們怎樣才能做到這一點呢&#xff1f;俗話說&#xff0c;工欲善其事&#xff0c;必先利其器。因此&#xff0c;首先了解 10 個鋒利的 Android 文件傳輸應用程序&#x…

AlphaEvolve:LLM驅動的算法進化革命與科學發現新范式

AlphaEvolve&#xff1a;LLM驅動的算法進化革命與科學發現新范式 本文聚焦Google DeepMind最新發布的AlphaEvolve&#xff0c;探討其如何通過LLM與進化算法的結合&#xff0c;在數學難題突破、計算基礎設施優化等領域實現革命性進展。從48次乘法優化44矩陣相乘到數據中心資源利…

Java大師成長計劃之第24天:Spring生態與微服務架構之分布式配置與API網關

&#x1f4e2; 友情提示&#xff1a; 本文由銀河易創AI&#xff08;https://ai.eaigx.com&#xff09;平臺gpt-4-turbo模型輔助創作完成&#xff0c;旨在提供靈感參考與技術分享&#xff0c;文中關鍵數據、代碼與結論建議通過官方渠道驗證。 在微服務架構中&#xff0c;如何管理…

eSwitch manager 簡介

eSwitch manager 的定義和作用 eSwitch manager 通常指的是能夠配置和管理 eSwitch&#xff08;嵌入式交換機&#xff09;的實體或接口。在 NVIDIA/Mellanox 的網絡架構中&#xff0c;Physical Function&#xff08;PF&#xff09;在 switchdev 模式下充當 eSwitch manager&am…