更新记录
1.0.4(2026-08-31) 下载此版本
更新示例
1.0.3(2026-08-31) 下载此版本
更新说明
1.0.2(2026-08-25) 下载此版本
更新文档
查看更多平台兼容性
uni-app(3.8.3)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | - | - | √ | - | √ | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - | - |
lu-export-excel
文档说明
本插件基于 xlsx-js-style 在 UniApp 的 renderjs 层 实现 APP 端 Excel 文件导出,支持自定义文件名、表头、列宽与表头样式。
插件内部仅暴露 renderjs 模块(js_sdk/exportExcelRender.js + js_sdk/tool.js),并内置一个 easycom 组件 lu-excel-export(components/lu-excel-export/lu-excel-export.vue),封装好 prop 同步、trigger 翻转、结果回调与内置结果弹窗,业务侧无需手动 import,直接 <lu-excel-export /> 即可使用。
功能列表
- APP 端导出 Excel 文件,已在 UniApp + Vue2/3 环境测试通过;
- 自适应列宽(中英文混排按显示宽度估算);
- 表头样式可自定义(默认加粗,基于
xlsx-js-style); - 文件保存到
plus.io.PUBLIC_DOWNLOADS公共下载目录; - 通过 trigger 字段翻转触发导出,避免 prop 初始同步误触发;
- 内置重复同步守卫,避免 uni-app prop 重复同步导致重复导出;
- 公共组件自带结果弹窗(自绘全屏遮罩 + 居中卡片),并通过
@result事件回传完整结果。
目录
一、安装依赖
本插件依赖 xlsx-js-style(带样式的 xlsx 库):
# 使用 pnpm 安装依赖
pnpm add xlsx-js-style
# 或者使用 npm 安装依赖
npm install xlsx-js-style
# 或者使用 yarn 安装依赖
yarn add xlsx-js-style
二、核心参数说明
renderjs 内部使用一个 excelData 对象承载所有导出配置,字段如下(均有默认值,按需覆盖):
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fileName |
String |
"export" |
基础文件名,最终文件名默认拼接时间戳(格式:_YYYYMMDD_HHMMSS),非法字符会被替换为 _ |
sheetName |
String |
"Sheet1" |
Excel 工作表名称 |
hideNameTime |
Boolean |
false |
是否隐藏文件名后的时间戳;隐藏后重名文件会被直接覆盖 |
hideHeader |
Boolean |
false |
是否隐藏表头行(隐藏后仅显示数据行,且不应用表头样式) |
headerList |
Array<String> |
[] |
自定义表头文本;若为空,则自动取 Object.keys(list[0]) 作为表头 |
list |
Array<Object> |
[] |
导出的核心数据行,数组内为键值对对象格式;为空时 renderjs 端会忽略本次导出 |
trigger |
Number/String |
- | 触发位:业务侧每次 +1(或换成任意新值)即可驱动 renderjs 自动调用 startExport |
三、导出结果回调
renderjs 通过 ownerInstance.callMethod("handleExportExcel", res) 把结果回传到 Vue 层。
res 结构
| 字段 | 类型 | 说明 |
|---|---|---|
success |
Boolean |
导出是否成功,true 表示成功,false 表示失败 |
message |
String |
导出结果描述,如 "导出成功" / "导出失败" |
filePath |
String |
导出文件的本地路径(仅成功时有值) |
fileName |
String |
导出文件的名称(含 .xlsx 后缀,仅成功时有值) |
data |
Any |
导出失败时的错误对象(仅失败时有值) |
四、使用方式
方式一:easycom 组件(推荐)
插件内置组件 lu-excel-export,已通过 package.json 的 easycom 自动注册,业务页面无需手动 import,模板里直接写即可:
<template>
<lu-excel-export ref="excelExportRef" @result="onExportResult" />
</template>
组件位置:uni_modules/lu-export-excel/components/lu-excel-export/lu-excel-export.vue,封装好了 :prop 同步、trigger 翻转、结果回调与内置结果弹窗(自绘全屏遮罩 + 居中卡片),业务侧无需手动写 renderjs。
弹窗实现说明:组件不再使用
useModal()全局函数式弹窗(多次弹出时存在tempConfig残留问题,导致第二次弹窗内容空白),改用组件内置的自绘遮罩 + 卡片;同时始终emit('result', e),父组件可监听做自定义处理。
模板:
<template>
<lu-excel-export ref="excelExportRef" @result="onExportResult" />
</template>
默认行为(不开 silent):
- 成功:弹出组件内置遮罩卡片,分段显示「文件已保存到:
<filePath>」+「文件名:<fileName>」,确认按钮文字为「确定」; - 失败:弹出「
<errorTitle>」标题 + 「<errorPrefix><错误信息>」内容; - 同时始终
emit('result', e),父组件可监听做自定义处理(例如关闭 loading)。
Props:
| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
silent |
Boolean |
false |
设为 true 时关闭组件内置弹窗,仅 emit result |
successTitle |
String |
"导出成功" |
成功弹窗标题 |
errorTitle |
String |
"导出失败" |
失败弹窗标题 |
errorPrefix |
String |
"导出失败:" |
失败提示前缀(例如「导出失败:xxx」) |
注:
successTemplate模板字符串参数已在当前版本移除。成功结果固定按「文件已保存到:<filePath>」+「文件名:<fileName>」两段渲染,便于长路径/长文件名正确换行显示。
Events:
| 事件名 | 参数 | 说明 |
|---|---|---|
result |
(e: ExportResult) |
renderjs 回调结果,始终触发 |
方法(通过 ref 调用):
| 方法 | 参数 | 说明 |
|---|---|---|
trigger |
(payload: object) |
触发一次导出 |
trigger(payload) 的 payload 字段:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fileName |
String |
"export" |
导出文件名(不含后缀) |
sheetName |
String |
"Sheet1" |
工作表名 |
headerList |
Array<String> |
[] |
表头数组 |
list |
Array<Object> |
[] |
行数据 |
hideNameTime |
Boolean |
false |
是否隐藏文件名时间戳 |
hideHeader |
Boolean |
false |
是否隐藏表头 |
完整示例:
<template>
<view class="page">
<lu-excel-export ref="excelExportRef" @result="onExportResult" />
<view class="action-item" @click="handleExport(item)">导出</view>
</view>
</template>
<script setup>
import { ref } from "vue";
const excelExportRef = ref();
const handleExport = (item) => {
const headerList = ["姓名", "年龄", "出生日期", "随机", "备注"];
const list = new Array(1000).fill().map((_, i) => ({
name: `用户${i}`,
age: Math.floor(Math.random() * 30) + 20,
birthday: `user${i}@example.com`,
rod: `2025-01-01 23:22:44`,
remark: Date.now() + Math.random().toString(36),
}));
// 触发导出:组件内部会把 trigger 自增,renderjs 监听到翻转后自动调用 startExport
excelExportRef.value?.trigger({
fileName: item?.billName || "盘点详情",
sheetName: "Sheet1",
hideNameTime: false,
hideHeader: false,
headerList,
list,
});
};
const onExportResult = (e) => {
// 业务侧可选:关闭 loading、刷新列表等
uni.hideLoading();
console.log("导出结果:", e);
};
</script>
静默模式(自定义提示):
<lu-excel-export ref="excelExportRef" :silent="true" @result="onExportResult" />
const onExportResult = (e) => {
if (e?.success) {
uni.showToast({ title: "已保存", icon: "success" });
} else {
uni.showModal({ title: "失败", content: e?.message });
}
};
方式二:手动 import 公共组件
如果你的项目关闭了 easycom 或不想走自动注册,可以手动 import 组件并按需起别名:
<script>
import LuExcelExport from "@/uni_modules/lu-export-excel/components/lu-excel-export/lu-excel-export.vue";
export default {
components: { LuExcelExport },
};
</script>
<template>
<LuExcelExport ref="excelExportRef" @result="onExportResult" />
</template>
方式三:直接使用 renderjs
如需绕过公共组件,直接在页面模板中引入 renderjs:
<template>
<view class="page">
<view
class="excel-host"
:prop="excelData"
:change:prop="exportExcel.onPropChange"
@click="handleExport"
></view>
</view>
</template>
<script>
export default {
data() {
return {
excelData: {
fileName: "export",
sheetName: "Sheet1",
hideNameTime: false,
hideHeader: false,
headerList: [],
list: [],
trigger: 0,
},
};
},
methods: {
// 接收 renderjs 通过 ownerInstance.callMethod('handleExportExcel', res) 回调
handleExportExcel(res) {
console.log(res);
uni.showModal({
title: res.message,
content: res.filePath || res.message,
});
},
handleExport() {
const headerList = ["姓名", "年龄", "出生日期", "随机", "备注"];
const list = new Array(1000).fill().map((_, i) => ({
name: `用户${i}`,
age: Math.floor(Math.random() * 30) + 20,
birthday: `user${i}@example.com`,
rod: `2025-01-01 23:22:44`,
remark: Date.now() + Math.random().toString(36),
}));
// 注意:模板必须把 trigger 翻转,否则 renderjs 不会自动调用 startExport
this.excelData = {
...this.excelData,
fileName: "盘点详情",
sheetName: "Sheet1",
hideNameTime: false,
hideHeader: false,
headerList,
list,
trigger: (this.excelData?.trigger || 0) + 1,
};
},
},
};
</script>
<!-- 引入 Excel 导出插件(renderjs 模块,UniApp APP 端专用) -->
<script
module="exportExcel"
lang="renderjs"
src="@/uni_modules/lu-export-excel/js_sdk/exportExcelRender.js"
></script>
<style>
.excel-host {
display: none;
}
</style>
渲染节点要求:renderjs 要求组件至少有一个可渲染节点,否则会出现
$t.setAttribute is not a function异常;因此即使不显示,也必须保留<view ... :prop="..." :change:prop="...">这一节点。
五、工具函数说明
js_sdk/tool.js 暴露的工具函数(renderjs 内部已使用,业务侧如需复用可按需 import):
getCompactDateTime(date?)
生成紧凑格式时间字符串,形如 20251015_121532。
date:Date | number | string,默认new Date()。
arrayBufferToBase64(buffer)
将 ArrayBuffer / Uint8Array 等二进制数据转为 Base64 字符串(用于 plus.io 文件写入)。
saveArrayBufferToFile(fileName, arrayBuffer)
将二进制数据写入 plus.io.PUBLIC_DOWNLOADS 公共下载目录,返回 Promise<{ filePath, fileName }>。
getAutoColumnWidths(data)
基于数据字段计算自适应列宽(中文算 2、英文算 1),返回宽度数组。
setHeaderStyle(worksheetData, headerList, headerStyle?)
给 worksheet 的第 1 行表头单元格写入样式,默认仅 font.bold = true。更多样式字段可参考 xlsx-js-style 官方文档。headerStyle 可选参数示例:
setHeaderStyle(worksheet, ["姓名", "年龄"], {
font: {
bold: true,
italic: true,
sz: 12,
name: "华文琥珀",
strike: true,
underline: true,
color: { rgb: "FFFFFF" },
},
fill: {
fgColor: { rgb: "4CAF50" },
},
alignment: {
horizontal: "center",
vertical: "center",
},
// border: {
// top: { style: "thin", color: { rgb: "9417ed" } },
// bottom: { style: "thin", color: { rgb: "9417ed" } },
// left: { style: "thin", color: { rgb: "9417ed" } },
// right: { style: "thin", color: { rgb: "9417ed" } },
// },
});
// border.style 可选值:
// thin / medium / thick / dashed / dotted / hair / dashDot / dashDotDot
// mediumDashDot / mediumDashDotDot / mediumDashed / slantDashDot / double
六、关键注意事项
- 必须安装
xlsx-js-style(而非原生xlsx),因为setHeaderStyle需要带样式的版本; - trigger 翻转机制:renderjs 端
onPropChange仅在oldTrigger与trigger都是明确值且不同时触发导出,避免 prop 初始同步(0 vs null)误触发; - 重复同步守卫:renderjs 端会记忆
lastTrigger,prop 重复同步同一 trigger 时直接 return,不会重复导出; - 数据为空时忽略导出:
list为空数组时 renderjs 端直接 return,避免误生成空文件; - 文件名安全处理:
fileName中的/\:?"<>|会被替换为_; - 文件保存位置:默认
plus.io.PUBLIC_DOWNLOADS(公共下载目录),仅支持 APP 端; - 样式范围:仅表头单元格会应用样式,正文单元格样式需要自行扩展
setHeaderStyle类似工具函数或直接修改 worksheet; - 平台支持:仅 UniApp APP 端(vue2 / vue3),不支持 Web、小程序、H5;
- 公共组件渲染节点:
lu-excel-export.vue的.excel-export-root节点position: absolute; width: 0; height: 0; overflow: visible;(脱离文档流、不占布局),内部.excel-export-host为 renderjs prop-change 锚点(display: none),不能删除;同时根节点不能直接display: none,否则会裁剪掉内部的 fixed 定位遮罩弹层; - 公共组件结果弹窗:组件已内置自绘遮罩弹层(成功显示 filePath/fileName,失败显示错误信息),父组件也可通过
silent关闭内置弹窗并监听@result自定义处理。
七、常见问题排查
$t.setAttribute is not a function:模板中没有可渲染节点导致 renderjs 异常,保留一个挂:prop与:change:prop的<view>即可;- 首次点击没反应:检查
list是否为空数组(空时 renderjs 直接忽略); - 导出没触发:
trigger没有翻转,或oldTrigger/trigger中存在undefined/null;请确认每次都做trigger + 1; - 导出文件被覆盖:
hideNameTime = true时同名文件会被覆盖,需要保留历史请设为false; - 仅在 Android 验证通过:本插件目前仅在 Android 端测试验证;
- 表头样式不生效:确认安装了
xlsx-js-style而非xlsx;xlsx不支持单元格样式; - 中文列宽过窄:
getAutoColumnWidths已按中英文混排估算显示宽度,若仍有偏差可在tool.js中调整+ 2的 padding; - 公共组件遮罩被裁剪/不显示:检查
.excel-export-root是否被父级display: none或overflow: hidden包裹;组件根节点自身仅做绝对定位 0 尺寸 +overflow: visible。

收藏人数:
下载插件并导入HBuilderX
下载插件ZIP
赞赏(0)
下载 379
赞赏 1
下载 12640051
赞赏 1950
赞赏
京公网安备:11010802035340号