最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Vue3使用exceljs將excel文件轉(zhuǎn)化為html預(yù)覽最佳方案

 更新時(shí)間:2025年05月18日 10:05:48   作者:零凌林  
在企業(yè)應(yīng)用中,我們時(shí)常會遇到需要上傳并展示 Excel 文件的需求,以實(shí)現(xiàn)文件內(nèi)容的在線預(yù)覽,經(jīng)過一番探索與嘗試,筆者最終借助 exceljs 這一庫成功實(shí)現(xiàn)了該功能,本文將以 Vue 3 為例,演示如何實(shí)現(xiàn)該功能,需要的朋友可以參考下

前言

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

技術(shù)難點(diǎn)

基礎(chǔ)單元格和合并單元格的混合處理

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

富文本內(nèi)容格式的處理

excel文件展示

實(shí)際實(shí)現(xiàn)預(yù)覽效果

核心代碼

exceljs提供了合并區(qū)域的數(shù)據(jù),我們只需要根據(jù)合并區(qū)域去判斷什么時(shí)候該合并,就能很好的實(shí)現(xiàn)基礎(chǔ)單元格和合并單元格的混合繪制

  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-upload
      action=""
      :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 表格內(nèi)容
const themeColors = {
  0: "#FFFFFF", // 白色 √
  1: "#000000", // 黑色 √
  2: "#C9CDD1", // 灰色 √
  3: "#4874CB", // 藍(lán)色 √
  4: "#D9E1F4", // 淺藍(lán) √
  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 轉(zhuǎn) RGB
    }
    if (cell.fill.fgColor.theme !== undefined) {
      return themeColors[cell.fill.fgColor.theme] || "#FFFFFF"; // 主題色轉(zhuǎn)換
    }
  }
 
  return ""; // 無顏色
};
// 獲取單元格字體顏色
const getCellFontColor = (cell) => {
  if (cell.font && cell.font.color && cell.font.color.argb) {
    return `#${cell.font.color.argb.substring(2)}`; // ARGB 轉(zhuǎn) RGB
  }
  if (cell.font && cell.font.color && cell.font.color.theme) {
    return themeColors[cell.font.color.theme] || "#000"; // 主題色轉(zhuǎn)換
  }
 
  return "#000"; // 默認(rèn)黑色
};
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 表格內(nèi)容
};
// 處理常規(guī)單元格內(nèi)容
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 : "";
};
// 處理合并單元格內(nèi)容
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 并轉(zhuǎn)換成 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); // 獲取當(dāng)前工作表的索引
 
    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這個(gè)庫的作用是啥?

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

主要特性

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

使用場景

ExcelJS 廣泛應(yīng)用于需要與 Excel 文件進(jìn)行交互的應(yīng)用程序開發(fā)中,比如:

  • 數(shù)據(jù)報(bào)告生成
  • 數(shù)據(jù)導(dǎo)入/導(dǎo)出功能實(shí)現(xiàn)
  • 在線 Excel 編輯器

示例代碼片段

這里是一個(gè)簡單的示例,展示如何使用 ExcelJS 創(chuàng)建一個(gè)新的工作簿并添加一些數(shù)據(jù):

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

 這個(gè)例子展示了如何創(chuàng)建一個(gè)新的 Excel 文件,并向其中添加一些簡單數(shù)據(jù)。ExcelJS 的靈活性和強(qiáng)大功能使其成為處理 Excel 文件的一個(gè)優(yōu)秀選擇。

npm上的puppeteer庫是做什么的?

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

核心功能

  1. 無頭瀏覽器控制
    可啟動 Headless 模式(無界面)或完整瀏覽器,執(zhí)行自動化任務(wù)(如點(diǎn)擊、輸入、導(dǎo)航等)。

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

  3. 生成截圖與 PDF
    精確截取網(wǎng)頁全屏、指定區(qū)域,或?qū)㈨撁鎸?dǎo)出為 PDF(保留樣式)。

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

  5. 性能分析
    監(jiān)控頁面加載速度、資源請求,優(yōu)化性能。

 典型使用場景

  • 數(shù)據(jù)抓取:爬取電商價(jià)格、社交媒體內(nèi)容等動態(tài)加載的數(shù)據(jù)。

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

  • 預(yù)渲染:為 SEO 生成靜態(tài)化內(nèi)容,解決 SPA 首屏加載問題。

  • 生成報(bào)告:將數(shù)據(jù)可視化頁面導(dǎo)出為 PDF 或圖片存檔。

 基礎(chǔ)示例

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

安裝與依賴

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

npm install puppeteer

優(yōu)勢

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

  • 功能全面:支持網(wǎng)絡(luò)請求攔截、Cookie 管理、模擬設(shè)備(如手機(jī)/平板)等。

  • 社區(qū)活躍:豐富的文檔和第三方工具(如 puppeteer-cluster 多任務(wù)優(yōu)化)。

若你需要處理復(fù)雜的網(wǎng)頁交互或動態(tài)內(nèi)容,Puppeteer 是一個(gè)高效且靈活的選擇。

vue中為什么切換動態(tài)組件需要使用shallowRef ?

在 Vue 3 中,使用 shallowRef 來管理動態(tài)組件的切換,主要是出于性能優(yōu)化和避免不必要的深度響應(yīng)式追蹤的考慮。以下是詳細(xì)解釋:

1. ref vs shallowRef 的核心區(qū)別

會對其包裹的值進(jìn)行深度響應(yīng)式轉(zhuǎn)換(遞歸將對象屬性轉(zhuǎn)為響應(yīng)式)。

僅對值的引用變化進(jìn)行響應(yīng)式追蹤,不會深度遞歸轉(zhuǎn)換內(nèi)部屬性。

2. 動態(tài)組件的場景分析

當(dāng)使用 <component :is="currentComponent"> 切換組件時(shí):

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

3. 為什么 shallowRef 更合適?

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

4. 示例對比

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

5. 官方建議

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

“如果你確實(shí)需要響應(yīng)性,可以使用 shallowRef。”

在動態(tài)組件切換場景中,shallowRef 通過避免深度響應(yīng)式轉(zhuǎn)換,在保證功能正確性的同時(shí),提升了性能并規(guī)避了潛在問題。這正是它與 ref 的核心區(qū)別所在。

以上就是Vue3使用exceljs將excel文件轉(zhuǎn)化為html預(yù)覽最佳方案的詳細(xì)內(nèi)容,更多關(guān)于Vue3 exceljs將excel轉(zhuǎn)html預(yù)覽的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Vue2.0 實(shí)現(xiàn)頁面緩存和不緩存的方式

    Vue2.0 實(shí)現(xiàn)頁面緩存和不緩存的方式

    今天小編就為大家分享一篇Vue2.0 實(shí)現(xiàn)頁面緩存和不緩存的方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • 解決vue無法加載文件D:\Program Files\nodejs\node_global\vue.ps1,因?yàn)樵诖讼到y(tǒng)上禁止運(yùn)行腳本

    解決vue無法加載文件D:\Program Files\nodejs\node_global\vue.ps1,

    這篇文章主要給大家介紹了關(guān)于解決vue無法加載文件D:\Program Files\nodejs\node_global\vue.ps1,因?yàn)樵诖讼到y(tǒng)上禁止運(yùn)行腳本的相關(guān)資料,這個(gè)報(bào)錯是由于在系統(tǒng)上禁止運(yùn)行腳本導(dǎo)致的,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • 基于Vue3+西瓜視頻播放器(xgplayer)移動端直播解決方案

    基于Vue3+西瓜視頻播放器(xgplayer)移動端直播解決方案

    在現(xiàn)代前端開發(fā)中,視頻播放功能越來越常見,從在線教育到娛樂平臺都離不開高質(zhì)量的視頻播放器,這篇文章主要介紹了基于Vue3+西瓜視頻播放器(xgplayer)移動端直播的相關(guān)資料,需要的朋友可以參考下
    2026-02-02
  • vue下跨域設(shè)置的相關(guān)介紹

    vue下跨域設(shè)置的相關(guān)介紹

    本篇文章主要介紹了vue下跨域設(shè)置的相關(guān)介紹,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-08-08
  • Vue實(shí)現(xiàn)表格合并與拆分的示例代碼

    Vue實(shí)現(xiàn)表格合并與拆分的示例代碼

    在Vue應(yīng)用程序中,表格是一個(gè)非常常見的組件,在這篇文章中,我們將介紹如何在Vue中進(jìn)行表格的合并和拆分,感興趣的小伙伴可以了解一下
    2023-06-06
  • 如何修改vue-treeSelect的高度

    如何修改vue-treeSelect的高度

    這篇文章主要介紹了如何修改vue-treeSelect的高度,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Vue.js中集成Socket.IO實(shí)現(xiàn)實(shí)時(shí)聊天功能

    Vue.js中集成Socket.IO實(shí)現(xiàn)實(shí)時(shí)聊天功能

    隨著 Web 技術(shù)的發(fā)展,實(shí)時(shí)通信成為現(xiàn)代 Web 應(yīng)用的重要組成部分,Socket.IO 是一個(gè)流行的庫,支持及時(shí)、雙向與基于事件的通信,適用于各種平臺和設(shè)備,本文將介紹如何在 Vue.js 項(xiàng)目中集成 Socket.IO,實(shí)現(xiàn)一個(gè)簡單的實(shí)時(shí)聊天應(yīng)用,需要的朋友可以參考下
    2024-12-12
  • Vue3如何清空Reactive定義的數(shù)組

    Vue3如何清空Reactive定義的數(shù)組

    這篇文章主要介紹了Vue3如何清空Reactive定義的數(shù)組問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2023-10-10
  • 對vue生命周期的深入理解

    對vue生命周期的深入理解

    這篇文章主要給大家介紹了關(guān)于對vue生命周期的深入理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Vue3自定義Hooks函數(shù)的使用詳解

    Vue3自定義Hooks函數(shù)的使用詳解

    vue3 中的 hooks 就是函數(shù)的一種寫法,就是將文件的一些單獨(dú)功能的js代碼進(jìn)行抽離出來進(jìn)行封裝使用,下面我們就來看看vue3中自定義Hooks函數(shù)的使用吧
    2023-09-09

最新評論

乌鲁木齐市| 台南县| 永定县| 栾城县| 西藏| 金华市| 淄博市| 汉源县| 昌都县| 元阳县| 大悟县| 牙克石市| 军事| 古丈县| 奎屯市| 绩溪县| 河东区| 新巴尔虎左旗| 福州市| 伊金霍洛旗| 双桥区| 垦利县| 金湖县| 龙胜| 合作市| 西吉县| 浏阳市| 镇宁| 上栗县| 高碑店市| 逊克县| 镇宁| 长宁区| 咸丰县| 同仁县| 荆门市| 江西省| 商水县| 娱乐| 扶余县| 江华|