欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

前言

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

技術(shù)難點

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

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

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

excel文件展示

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

核心代碼

exceljs提供了合并區(qū)域的數(shù)據(jù),我們只需要根據(jù)合并區(qū)域去判斷什么時候該合并,就能很好的實現(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", // 藍色 √
  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 轉(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"; // 默認黑色
};
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); // 獲取當前工作表的索引
 
    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 格式)。它允許開發(fā)者通過編程方式處理 Excel 文檔,包括創(chuàng)建新工作簿、添加數(shù)據(jù)、格式化單元格、插入圖表等。這個庫可以在服務(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 文件。
  • 公式和計算:可以添加公式到單元格,并支持基本的 Excel 計算。
  • 圖表支持:能夠在 Excel 文件中創(chuàng)建圖表。
  • 圖片和繪圖:支持向 Excel 文件中添加圖片和繪制圖形。

使用場景

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

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

示例代碼片段

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

const ExcelJS = require('exceljs');
 
// 創(chuàng)建一個新的工作簿
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('文件保存成功');
    });

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

npm上的puppeteer庫是做什么的?

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

核心功能

  1. 無頭瀏覽器控制
    可啟動 Headless 模式(無界面)或完整瀏覽器,執(zhí)行自動化任務(wù)(如點擊、輸入、導(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 交互),生成測試報告。

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

 典型使用場景

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

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

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

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

 基礎(chǔ)示例

const puppeteer = require('puppeteer');
 
(async () => {
  // 啟動瀏覽器(默認 Headless 模式)
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  
  // 導(dǎ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)勢

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

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

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

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

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

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

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

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

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

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

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

  • 組件對象本身是穩(wěn)定的
    動態(tài)組件的核心操作是替換整個組件對象(如 currentComponent.value = NewComponent),而不是修改組件對象的內(nèi)部屬性。
  • 組件對象可能很大
    一個組件對象(如導(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)式代理。
  • 符合實際需求
    動態(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 的所有屬性,但實際只需要引用變化觸發(fā)更新
 
 
 
// 使用 shallowRef(推薦)
 
import { shallowRef } from 'vue';
 
 
 
const currentComponent = shallowRef(HeavyComponent);
 
// 僅追蹤 currentComponent.value 的引用變化,高效且安全

5. 官方建議

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

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

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

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

相關(guān)文章

  • Vue實現(xiàn)下載文件而非瀏覽器直接打開的方法

    Vue實現(xiàn)下載文件而非瀏覽器直接打開的方法

    對于瀏覽器來說,文本、圖片等可以直接打開的文件,不會進行自動下載,下面這篇文章主要給大家介紹了關(guān)于Vue實現(xiàn)下載文件而非瀏覽器直接打開的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-05-05
  • 詳解Vue基于vue-quill-editor富文本編輯器使用心得

    詳解Vue基于vue-quill-editor富文本編輯器使用心得

    這篇文章主要介紹了Vue基于vue-quill-editor富文本編輯器使用心得,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • 傳說中VUE的語法糖到底是做什么的

    傳說中VUE的語法糖到底是做什么的

    從接觸Vue我們就知道 v-model是實現(xiàn)數(shù)據(jù)雙向綁定的那他能實現(xiàn)綁定的原理到底是啥?最常見的語法糖 v-model,今天通過案例給大家詳細介紹下,需要的朋友參考下吧
    2021-09-09
  • 聊聊element-ui 側(cè)邊欄的router問題

    聊聊element-ui 側(cè)邊欄的router問題

    這篇文章主要介紹了關(guān)于element-ui 側(cè)邊欄的router問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-05-05
  • vue中關(guān)于template報錯等問題的解決

    vue中關(guān)于template報錯等問題的解決

    這篇文章主要介紹了vue中關(guān)于template報錯等問題的解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-04-04
  • vue2.0 路由模式mode=

    vue2.0 路由模式mode="history"的作用

    這篇文章主要介紹了vue2.0 路由模式mode="history"的作用,非常不錯,具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2018-10-10
  • vue+watermark-dom實現(xiàn)頁面水印效果(示例代碼)

    vue+watermark-dom實現(xiàn)頁面水印效果(示例代碼)

    watermark.js 是基于 DOM 對象實現(xiàn)的 BS 系統(tǒng)的水印,確保系統(tǒng)保密性,安全性,降低數(shù)據(jù)泄密風險,簡單輕量,支持多屬性配置,本文將通過 vue 結(jié)合 watermark-dom 庫,教大家實現(xiàn)簡單而有效的頁面水印效果,感興趣的朋友跟隨小編一起看看吧
    2024-07-07
  • vue使用動態(tài)添加路由(router.addRoutes)加載權(quán)限側(cè)邊欄的方式

    vue使用動態(tài)添加路由(router.addRoutes)加載權(quán)限側(cè)邊欄的方式

    這篇文章主要介紹了vue使用動態(tài)添加路由(router.addRoutes)加載權(quán)限側(cè)邊欄的方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • vue實現(xiàn)戶籍管理系統(tǒng)

    vue實現(xiàn)戶籍管理系統(tǒng)

    這篇文章主要介紹了Vue實現(xiàn)戶籍管理系統(tǒng),戶籍信息的添加與刪除,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-05-05
  • 基于webpack4+vue-cli3項目實現(xiàn)換膚功能

    基于webpack4+vue-cli3項目實現(xiàn)換膚功能

    這篇文章主要介紹了基于webpack4+vue-cli3項目的換膚功能,文中是通過scss+style-loader/useable做換膚功能,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-07-07

最新評論