vue3中预览Excel文件

发布于:2025-05-17 ⋅ 阅读:(19) ⋅ 点赞:(0)

1.前言

有时候项目中需要预览Excel文件,特别是对于.xls格式的Excel文件许多插件都不支持,经过尝试,最终有三种方案可以实现.xlsx和.xls格式的Excel文件的预览,各有优缺点

2.luckyexcel插件

2.1说明

该插件优点在于能保留源文件的样式和保留图片,缺点在于只支持.xlsx,无法编辑更改(可能是我没有去查找资料),适用于需要保留样式只用于预览不用于编辑的场景

2.2使用过程

2.2.1安装
npm install luckyexcel
2.2.2引入

引入方式有两种

(1)使用CDN引入
<script src="https://cdn.jsdelivr.net/npm/luckyexcel/dist/luckyexcel.umd.js"></script>

这个路径意思是会拉取到最新的luckysheet代码,但是如果Luckysheet刚刚发布,jsdelivr网站可能还没来得及从npm上同步过去,故而使用这个路径还是会拉到上一个版本,我们推荐您直接指定版本。

<script src="https://cdn.jsdelivr.net/npm/luckysheet@2.1.12/dist/luckysheet.umd.js"></script>
(2)本地静态文件方式引入

先从luckyexcel项目中获静态资源用https://gitcode.com/gh_mirrors/lu/Luckyexcel

在public文件夹中新建luckyexcel文件夹,将静态资源全部放入该文件夹中

两种引入方式前提都已说明,下面开始引入

在项目入口文件index.html中引入

// 实用CDN方式引入-拉取最新代码



<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="renderer" content="webkit">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <link rel="icon" href="/favicon.ico">

  <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>
  
  <title>kanno</title>
</head>
// 使用静态文件方式引入
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="renderer" content="webkit">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <link rel="icon" href="/favicon.ico">

  <link rel='stylesheet' href='/luckyexcel/plugins/css/pluginsCss.css' />
  <link rel='stylesheet' href='/luckyexcel/plugins/plugins.css' />
  <link rel='stylesheet' href='/luckyexcel/css/luckysheet.css' />
  <link rel='stylesheet' href='/luckyexcel/assets/iconfont/iconfont.css' />
  <script src="/luckyexcel/plugins/js/plugin.js"></script>
  <script src="/luckyexcel/luckysheet.umd.js"></script>
  
  <title>kanno</title>
</head>
2.2.3使用
<template>
    <div id="luckysheet" ref="luckysheet" style="width:100%;height:100%;position: absolute;left: 0;top: 0;z-index: 0;" ></div>
</template>

<script setup>
import LuckyExcel from 'luckyexcel'
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue';
const props = defineProps({
    excelUrl: {
        default:'',
        type: String
    }
});

// const emit = defineEmits([]);
let { excelUrl } = toRefs(props)

onMounted(()=>{
    viewOpen('Excel文件')
})
async function viewOpen(fileName) {
  const data = await fetchBlob(excelUrl.value);
    console.log("excelUrl.value",excelUrl.value);
    
  if (!data) {
    console.log("无法获取文件数据");
    return;
  }

  LuckyExcel.transformExcelToLucky(data, function (exportJson, luckysheetfile) {
    if (!exportJson || exportJson.sheets == null || exportJson.sheets.length == 0) {
      console.log("出错了");
      return;
    }
    
    if (window.luckysheet) {
      window.luckysheet.destroy();
    }

    window.luckysheet.create({
      data: exportJson.sheets,
      title: fileName,
      userInfo: exportJson.info?.creator,
      container: 'luckysheet', // 设定DOM容器的id
      showtoolbar: false, // 是否显示工具栏
      showinfobar: false, // 是否显示顶部信息栏
      showstatisticBar: false, // 是否显示底部计数栏
      sheetBottomConfig: false, // sheet页下方的添加行按钮和回到顶部按钮配置
      allowEdit: false, // 是否允许前台编辑
      enableAddRow: false, // 是否允许增加行
      enableAddCol: false, // 是否允许增加列
      sheetFormulaBar: false, // 是否显示公式栏
      enableAddBackTop: false, // 返回头部按钮
      showsheetbar: false, // 是否显示底部sheet页按钮
      showsheetbarConfig: {
        add: false,
        menu: false
      }
    });
  });
}

async function fetchBlob(url) {
  try {
    const response = await fetch(url);
    if (!response.ok) throw new Error("Network response was not ok.");
    return await response.blob();
  } catch (error) {
    console.error("Failed to fetch blob:", error);
    return null;
  }
}
</script>
2.2.4效果

3.微软在线查看excel文件

3.1说明

微软在线查看excel是使用iframe嵌入微软查看的页面,有点在于开发简单,能支持.xlsx和.xls格式,缺点在于无法编辑(可能通过注册微软账号可以进行编辑)和限制文件大小在5M以下,需要文件能通过链接访问,适用于小文件查看

3.2使用

<iframe id="iframeId" scrolling="no" frameborder="0" width="100%" height="118%"
              style="margin-top: -80px;"></iframe>
let iframeId = document.getElementById('iframeId')
iframeId.src = `https://view.officeapps.live.com/op/view.aspx?src=` + encodeURIComponent(data.data.fileUrl) // 微软网页

3.3代码说明

Your request has been blocked. This could be due to several reasons.是微软用来在线查看excel文件的网页;encodeURIComponent()方法是用来解析文件地址,无需引入

3.4效果展示

4.使用XLSX插件

4.1说明

XLSX支持.xlsx和.xls格式的Excel文件的预览,能通过js方法来更改excel表格,可操作性好,缺点在于不能保留源文件样式、渲染出来的表格和源文件有出入,适用于简单表格文件的预览

4.2安装
npm install xlsx
4.3引入使用
<template>
    <div :id="'excelDom'+id" style="width: 100%;height: 100%;overflow: auto;"></div>
</template>

<script setup>
import * as XLSX from "xlsx";
import axios from "axios";
import { ref, reactive, computed, onMounted, onUnmounted } from 'vue';
const props = defineProps({
    excelUrl: {
        default: '',
        type: String
    },
    id:{
        default: 1,
        type: Number
    }
});

// const emit = defineEmits([]);
let { excelUrl,id } = toRefs(props)

// Excel显示
getFileObjectFromUrl(excelUrl.value, function (file) {
    loadExcelAndRender(file);
});
function getFileObjectFromUrl(url, callback) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob'; // 重要:设置响应类型为blob

    xhr.onload = function () {
        if (this.status === 200) {
            // 请求成功,this.response包含Blob对象
            var blob = this.response;
            let fileName = new Date().getTime()
            // 创建File对象
            var file = new File([blob], fileName + '.xlsx', { type: blob.type });
            // 调用回调函数,传入File对象
            callback(file);
        } else {
            console.error('Failed to download file:', this.status);
        }
    };

    xhr.onerror = function () {
        console.error('Request error');
    };

    xhr.send();
}
async function loadExcelAndRender(file) {
    try {
        const reader = new FileReader();
        reader.onload = function (e) {
            let excelDom = document.getElementById('excelDom'+id.value);
            const data = new Uint8Array(e.target.result);
            const workbook = XLSX.read(data, { type: 'array' });
            const firstSheetName = workbook.SheetNames[0]; // 获取第一个sheet的名称
            const worksheet = workbook.Sheets[firstSheetName];
            const html = XLSX.utils.sheet_to_html(worksheet, { id: firstSheetName }); // 只渲染第一个sheet
            excelDom.innerHTML = html; // 将HTML渲染到指定的div中

            // 动态添加细线表格样式
            const table = excelDom.querySelector('table');
            if (table) {
                // 设置表格整体样式
                table.style.borderCollapse = 'collapse'; // 合并边框
                table.style.width = '100%'; // 宽度占满容器
                table.style.fontSize = '12px'; // 字体大小
                table.style.lineHeight = '1.5'; // 行高
                table.style.textAlign = 'center'; // 文字居中
                table.style.border = '1px solid #ddd'; // 外边框细线

                // 设置表头样式
                const thead = table.querySelector('tr');
                if (thead) {
                    thead.style.backgroundColor = '#f2f2f2'; // 表头背景颜色
                    thead.style.fontWeight = 'bold'; // 表头字体加粗
                    thead.style.whiteSpace = 'nowrap'; // 防止内容换行,确保宽度自适应
                }

                // 设置单元格样式
                const cells = table.querySelectorAll('td, th');
                cells.forEach(cell => {
                    cell.style.border = '1px solid #ddd'; // 细线边框
                    cell.style.padding = '5px'; // 内边距
                });
                // 为所有非表头的 td 添加点击事件
                const tds = table.querySelectorAll('tbody td'); // 获取 tbody 中的 td
                tds.forEach((td) => {
                    td.addEventListener('click', () => {
                        // 清除所有单元格的背景色
                        tds.forEach(cell => {
                            cell.style.backgroundColor = ''; // 清除背景色
                        });

                        // 为当前点击的单元格设置背景色
                        td.style.backgroundColor = '#cfe2ff'; // 设置背景色为浅蓝色

                        // 计算行号和列号
                        const row = td.parentNode.rowIndex; // 获取行号(从 0 开始)
                        const col = td.cellIndex; // 获取列号(从 0 开始)
                    });
                });
            }
        };
        reader.readAsArrayBuffer(file);
    } catch (error) {
        console.error('Error loading or rendering Excel:', error);
    }
}

</script>


网站公告

今日签到

点亮在社区的每一天
去签到