前端Excel表格导入导出,包括合并单元格,表格自定义样式等
表格数据导入
读取导入Excel表格数据这里采用的是 xlsx 插件
npm i xlsx
读取excel需要通过 XLSX.read(data, {type: type}) 方法来实现,返回一个叫WorkBook的对象,type主要取值如下:
- base64: 以base64方式读取;
- binary: BinaryString格式(byte n is data.charCodeAt(n))
- string: UTF8编码的字符串;
- buffer: nodejs Buffer;
- array: Uint8Array,8位无符号数组;
- file: 文件的路径(仅nodejs下支持);
同时需要用到插件自身的工具类XLSX.utils来对worksheet进行解析
- XLSX.utils.sheet_to_csv:生成CSV格式
- XLSX.utils.sheet_to_txt:生成纯文本格式
- XLSX.utils.sheet_to_html:生成HTML格式
- XLSX.utils.sheet_to_json:输出JSON格式
下面用一个 vue 的组件来演示一下
<template>
<div class="read_excel_file">
<slot></slot>
<input
class="file-input"
ref="readexcel_input"
type="file"
:accept="SheetJSFT"
@change="change"
/>
</div>
</template>
<script>
import XLSX from 'xlsx'
export default {
data() {
return {
SheetJSFT: '.xlsx',
}
},
mounted() {
// 绑定插槽点击触发导入文件
if (this.$slots && this.$slots.default && this.$slots.default.length > 0) {
this.$slots.default[0].elm.addEventListener(
'click',
this.openExcel.bind(this),
)
}
},
methods: {
// 点击打开导入excel
openExcel() {
let uploadBtn = this.$refs['readexcel_input']
uploadBtn.click()
},
// 文件导入时
change(evt) {
const files = evt.target.files
if (!/\.xlsx$/.test(files[0].name)) {
this.$emit('validate', false)
this.$emit('file-change', {
name: files[0].name,
})
console.error('请选择xlsx格式文件')
return false
} else {
this.$emit('validate', true)
}
if (files && files[0]) this.file(files[0])
},
// 数据读取
file(file) {
const reader = new FileReader()
reader.onload = e => {
const bstr = e.target.result
const wb = XLSX.read(bstr, { type: 'binary' }) // 这里使用type为binary
const wsname = wb.SheetNames[0]
const ws = wb.Sheets[wsname]
const data = XLSX.utils.sheet_to_json(ws, {
header: 1,
// blankrows: false,
}) // 读取json格式
this.formatData(data, file.name, ws['!merges'])
}
reader.readAsBinaryString(file)
},
// 数据格式化
formatData(list, name, merges) {
let arr = []
for (let i = 1; i < list.length; i++) {
if (list[i].length > 0) {
let obj = {}
list[i].map((v, j) => {
obj[list[0][j]] = v
})
arr.push(obj)
}
}
this.$emit('file-change', {
header: list[0],
body: arr,
name: name,
merges: merges,
})
// 必须清空input的value属性,不然第二次选择同样的文件,不会触发change事件。
this.$refs['readexcel_input'].value = ''
},
},
}
</script>
<style lang="scss" scoped>
.read_excel_file {
display: inline-block;
.file-input {
width: 0;
height: 0;
}
}
</style>
组件的具体使用如下
<template>
<div class="cs">
<ReadExcel @file-change="excelFileChange">
<div class="import-button">导入</div>
</ReadExcel>
</div>
</template>
<script>
import ReadExcel from './components/ReadExcel.vue'
export default {
components: {
ReadExcel,
},
methods: {
excelFileChange(data) {
let { merges, body, name, header } = data
console.log(merges, body, name, header)
},
},
}
</script>
接下来,我们尝试导入以下的表格
导出的数据(merges, body, name, header)如下
如此,便拿到了表格中的数据
导出excel表格
这里展示两种导出表格的方法
1、xlsx插件导出
这里还是用到xlsx插件
这里直接做一个小demo展示
function exportExcel(header, body, merges, wscols, wsrows, fileName) {
body.unshift(header)
const ws = XLSX.utils.aoa_to_sheet(body)
const wb = XLSX.utils.book_new()
ws['!cols'] = wscols
ws['!rows'] = wsrows
ws['!merges'] = merges
XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
// 生成excel
XLSX.writeFile(wb, `${fileName}.xlsx`)
}
// 设置表格头部
let header = [
'*手机号码',
'*订单编号',
'*商品编号',
'*数量',
'*订单支付类型',
'*订单总金额¥',
'*订单实付金额¥',
]
// 设置表格数据
let body = [
['18600000002', 'svp000002', 'sp002', '1', '微信支付', '1100', '1100'],
[undefined, undefined, 'sp003', '2', undefined, undefined, undefined],
[undefined, undefined, 'sp004', '1', undefined, undefined, undefined],
]
// 设置合并单元格
let merges = [
{ e: { c: 0, r: 3 }, s: { c: 0, r: 1 } },
{ e: { c: 1, r: 3 }, s: { c: 1, r: 1 } },
{ e: { c: 4, r: 3 }, s: { c: 4, r: 1 } },
{ e: { c: 5, r: 3 }, s: { c: 5, r: 1 } },
{ e: { c: 6, r: 3 }, s: { c: 6, r: 1 } },
]
// 指定每一列的宽度
let wscols = [
{ wch: 20 },
{ wch: 20 },
{ wch: 30 },
{ wch: 30 },
{ wch: 30 },
{ wch: 30 },
{ wch: 30 },
]
// 指定每一行的高度
let wsrows = [{ hpx: 20 }]
exportExcel(header, body, merges, wscols, wsrows, '生成excel文件')
导出结果如下
导出是导出成功,但是只有光秃秃的数据
那么这里如果要设置单元格的样式该怎么做呢?
如果单纯使用xlsx插件是无法设置单元格的样式的,似乎有个xlsx的pro专业版可以做到,但是是收费的; 也有使用免费的xlsx-style实现设置样式
npm i xlsx-style
用xlsx-style确实可以实现设置样式,但是像我们一开始导入的excel文件中的表头中(如下图),有一个单元格中存在两种不同颜色的文本的情况,
这种情况下,笔者用xlsx-style也实现不了,所以这里不详诉xlsx-style的使用方法,我们试下第二种导出excel的方法
2、使用html table标签导出excel
这里是用table标签直接生成excel文件
直接上代码
function tableHtmlCompute(str) {
return (
"<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel'><head><!--[if gte mso 9]><xml>" +
'<x:ExcelWorkbook>' +
'<x:ExcelWorksheets>' +
'<x:ExcelWorksheet>' +
'<x:WorksheetOptions><x:Print><x:ValidPrinterInfo /></x:Print></x:WorksheetOptions>' +
'</x:ExcelWorksheet>' +
'</x:ExcelWorksheets>' +
'</x:ExcelWorkbook></xml><![endif]--> ' +
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body>' +
'<table border="1" cellspacing="1" cellpadding="1">' +
'<tr>' + // 这里是表头
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">*</span><span>手机号码</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">*</span><span>订单编号</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">*</span><span>商品编号</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">*</span><span>数量</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">*</span><span>订单支付类型</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">*</span><span>订单总金额¥</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">*</span><span>订单实付金额¥</span></td>' +
'</tr>' +
'<tr>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">必填项</span><br style="mso-data-placement:same-cell"/><span>1、学员购买商品收货填写的手机号</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">必填项</span><br style="mso-data-placement:same-cell"/><span>1、填写导入的订单在售卖平台的订单编号</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">必填项</span><br style="mso-data-placement:same-cell"/><span>1、上架商品时候填写的“售卖平台商品编号”</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">必填项</span><br style="mso-data-placement:same-cell"/><span>1、购买商品的总数量</span><br style="mso-data-placement:same-cell"/><span>2、填写的数量>=1,且为整数。</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">必填+单选</span><br style="mso-data-placement:same-cell"/><span>1、选项</span><br style="mso-data-placement:same-cell"/><span>微信支付</span><br style="mso-data-placement:same-cell"/><span>支付宝支付</span><br style="mso-data-placement:same-cell"/><span>网银支付</span><br style="mso-data-placement:same-cell"/><span>pos机支付</span><br style="mso-data-placement:same-cell"/><span>银行汇款</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">必填项</span></td>' +
'<td style="background:rgb(217,225,242);mso-number-format:@"><span style="color: rgb(255,0,0)">必填项</span></td>' +
'</tr>' +
str +
'</table></body></html>'
)
}
function excelExport(str) {
let html = tableHtmlCompute(str)
let blob = new Blob([html], {
type: 'text/plain;charset=utf-8',
})
//解决中文乱码问题
blob = new Blob([String.fromCharCode(0xfeff), blob], {
type: blob.type,
})
let a = document.createElement('a')
a.style.display = 'none'
// 利用URL.createObjectURL()方法为 a 元素生成 blob URL
a.href = URL.createObjectURL(blob)
// 设置文件名
a.download = 'excel名字.xlsx'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
let body = [
{
mobile: '18600000002',
orderNumber: 'svp000002',
products: [
{
productNumber: 'sp002',
quantity: 1,
},
{
productNumber: 'sp003',
quantity: 2,
},
{
productNumber: 'sp004',
quantity: 1,
},
],
paymentType: '微信支付',
total: 1100,
paymenteds: 1100,
},
]
let header = [
'mobile',
'orderNumber',
'productNumber',
'quantity',
'paymentType',
'total',
'paymenteds',
]
let productsHeader = ['productNumber', 'quantity']
let html = ''
body.forEach(e => {
if (e.products && e.products.length) {
e.products.forEach((item, i) => {
let str = '<tr>'
if (i) {
productsHeader.forEach(key => {
str += `<td style="mso-number-format:\\@"><span>${
item[key] ? item[key] : ''
}</span></td>`
})
str += '</tr>'
} else {
// i===0;每一条数据的头部
header.forEach(key => {
if (productsHeader.includes(key)) {
str += `<td style="mso-number-format:\\@"><span>${
item[key] ? item[key] : ''
}</span></td>`
} else {
let val = e[key] ? e[key] : ''
str += `<td style="mso-number-format:\\@" rowspan=${e.products.length}><span>${val}</span></td>`
}
})
str += '</tr>'
}
html += str
})
}
})
excelExport(html)
导出结果如下
这里有以下几个注意点
1、上面有展示了如何在同一单元格内换行,如果需要在同一单元格内换行,需要用到以下代码
<br style="mso-data-placement:same-cell"/>
如果单纯只写br标签,不加后面的style="mso-data-placement:same-cell", 则它会出现两个单元格合并在一起的情况
2、style="mso-number-format:\@" 这个样式可以让单元格的格式被识别为文本,避免不必要的格式自动转换
前端Excel表格导入导出,包括合并单元格,表格自定义样式等的更多相关文章
- 在Asp.Net MVC中使用NPOI插件实现对Excel的操作(导入,导出,合并单元格,设置样式,输入公式)
前言 NPOI 是 POI 项目的.NET版本,它不使用 Office COM 组件,不需要安装 Microsoft Office,目前支持 Office 2003 和 2007 版本. 1.整个Ex ...
- Java导出Excel表,POI 实现合并单元格以及列自适应宽度(转载)
POI是apache提供的一个读写Excel文档的开源组件,在操作excel时常要合并单元格,合并单元格的方法是: sheet.addMergedRegion(new CellRangeAddress ...
- NPOI操作EXCEL(五)——含合并单元格复杂表头的EXCEL解析
我们在第三篇文章中谈到了那些非常反人类的excel模板,博主为了养家糊口,也玩命做出了相应的解析方法... 我们先来看看第一类复杂表头: ...... 博主称这类excel模板为略复杂表头模板(蓝色部 ...
- NPOI之Excel——合并单元格、设置样式、输入公式
首先建立一个空白的工作簿用作测试,并在其中建立空白工作表,在表中建立空白行,在行中建立单元格,并填入内容: //建立空白工作簿 IWorkbook workbook = new HSSFWorkboo ...
- NPOI之Excel——合并单元格、设置样式、输入公式、设置筛选等
首先建立一个空白的工作簿用作测试,并在其中建立空白工作表,在表中建立空白行,在行中建立单元格,并填入内容: //建立空白工作簿 IWorkbook workbook = new HSSFWorkboo ...
- .Net用字符串拼接实现表格数据相同时合并单元格
前言 最近在做项目通过GridView或Repeater绑定数据,如果两行或若干行某列值相同,需要进行合并单元格,但是实现过程中想到了字符串拼接,于是就没用绑定数据控件,而是用了html结合字符串实现 ...
- C#导出带有格式的Excel(列宽,合并单元格,显示边框线,加背景颜色等)
源地址:http://blog.sina.com.cn/s/blog_74f702e60101au55.html 导出excel相关设置:http://blog.csdn.net/wanmingtom ...
- php实现导出数据分类合并单元格功能
<?php $conn = mysql_connect("localhost","root","root"); $db = mysql ...
- 复杂的POI导出Excel表格(多行表头、合并单元格)
poi导出excel有两种方式: 第一种:从无到有的创建整个excel,通过HSSFWorkbook,HSSFSheet HSSFCell, 等对象一步一步的创建出工作簿,sheet,和单元格,并添加 ...
随机推荐
- python学习之基础内容
python基础内容① 什么是python? -一种计算机语言,计算机语言分为 -高级语言:python.java.Ruby.C#.C++...... -基础语言:C语言.汇编 -计算机可以直接执行基 ...
- HYSBZ 1734 二分
传送门 题面: 农夫 John 建造了一座很长的畜栏,它包括N (2 <= N <= 100,000)个隔间,这些小隔间依次编号为x1,...,xN (0 <= xi <= 1 ...
- golang 实现距离幂算法
func main() { var test []Pow var x1 Pow x1.distance = 110 x1.grade = 0.31 var x2 Pow x2.distance = 8 ...
- incubator-dolphinscheduler 如何在不写任何新代码的情况下,能快速接入到prometheus和grafana中进行监控
一.prometheus和grafana 简介 prometheus是由谷歌研发的一款开源的监控软件,目前已经贡献给了apache 基金会托管. 监控通常分为白盒监控和黑盒监控之分. 白盒监控:通过监 ...
- 走进docker-初识
什么是Docker容器? 容器是打包代码及其所有依赖项的软件的标准单元,因此应用程序可以从一个计算环境快速可靠地运行到另一个计算环境.Docker容器映像是一个轻量级的,独立的,可执行的软件软件包,其 ...
- Paperfolding HDU - 6822
传送门:https://vjudge.net/problem/HDU-6822 题意:给你一张无限的纸有四种折叠方式,并且在n次折叠后减两刀问最后纸张数量的数学期望. 思路:我们要得到一个通项公式对于 ...
- c/s应用程序自动更新组件GeneralUpdate3.2.1发布
一.组件简介 GeneralUpdate是基于.net standard 开发的一款(c/s应用)自动升级程序.该组件将更新的核心部分抽离出来方便应用于多种项目当中目前适用于wpf,控制台应用,win ...
- 从新建文件夹开始构建UtopiaEngine(1)
序言 在苦等了半年多之后,我终于开始了向往已久的实时NPR游戏引擎项目--Utopia Engine,这半年多一直为了构建这个引擎在做很多准备:多线程.动态链接库.脚本引擎.立即渲染GUI--统统吃了 ...
- go中semaphore(信号量)源码解读
运行时信号量机制 semaphore 前言 作用是什么 几个主要的方法 如何实现 sudog 缓存 acquireSudog releaseSudog semaphore poll_runtime_S ...
- vue 快速入门 系列 —— 虚拟 DOM
其他章节请看: vue 快速入门 系列 虚拟 DOM 什么是虚拟 dom dom 是文档对象模型,以节点树的形式来表现文档. 虚拟 dom 不是真正意义上的 dom.而是一个 javascript 对 ...