vue3中预览Excel文件

1.前言

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

2.luckyexcel插件

2.1说明

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

2.2使用过程

2.2.1安装
javascript 复制代码
npm install luckyexcel
2.2.2引入

引入方式有两种

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

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

javascript 复制代码
<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中引入

javascript 复制代码
// 实用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>
javascript 复制代码
// 使用静态文件方式引入
<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使用
javascript 复制代码
<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使用

html 复制代码
<iframe id="iframeId" scrolling="no" frameborder="0" width="100%" height="118%"
              style="margin-top: -80px;"></iframe>
javascript 复制代码
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安装
javascript 复制代码
npm install xlsx
4.3引入使用
javascript 复制代码
<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>
相关推荐
崔庆才丨静觅17 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606118 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了18 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅18 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅18 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅19 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment19 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅19 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊19 小时前
jwt介绍
前端
爱敲代码的小鱼19 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax