1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Vue前端实现excel的导入 导出 打印功能

Vue前端实现excel的导入 导出 打印功能

时间:2023-08-01 08:19:36

相关推荐

Vue前端实现excel的导入 导出 打印功能

目录

一、相关依赖下载二、excel导入功能三、table导出excel表格1.导出行数据2.导出table数据(也会导出合并单元格)3.导出二维数据的table数据4.导出合并单元格table数据四、table导出excel表格(带样式)1.导出带样式的excel2. 结合el-table,根据勾选的内容,导出excel表格五、打印功能1.直接使用window自带的打印功能: window.print()2.使用打印插件:vue-print-nb1、安装 vue-print-nb:2、在项目中引入 vue-print-nb:3、使用 vue-print-nb 实现打印功能① 实现方式1:打印区域设置id, 打印按钮绑定此 id② 实现方式2:打印区域设置id, 打印按钮进行打印配置③ 打印网址:打印指定url(同一个同源策略)对应的内容④ 打印预览功能⑤ 打印异步url⑥ 实现区域不打印方式⑦ vue-print-nb的API配置如下

一、相关依赖下载

导入导出依赖:

npm install xlsx@0.16.9

npm install xlsx-style@0.8.13 --save

安装xlsx-style,运行报错

This relative module was not found: ./cptable in ./node_modules/xlsx-style@0.8.13@xlsx-style/dist/cpexcel.js解决报错

在\node_modules\xlsx-style\dist\cpexcel.js 807行 的var cpt = require('./cpt' + 'able');改为:var cpt = cptable;

打印依赖:

npm install vue-print-nb@1.7.5 --save

二、excel导入功能

<template><div><el-uploadaction="#":before-upload="beforeUpload":show-file-list="false"accept=".xlsx, .xls"><el-button slot="trigger" size="small" type="primary">选取文件</el-button></el-upload><!-- 解析出来的数据 --><el-table :data="tableData"><el-table-column prop="日期" label="日期" width="180"> </el-table-column><el-table-column prop="姓名" label="姓名" width="180"> </el-table-column><el-table-column prop="地址" label="地址"> </el-table-column></el-table></div></template><script>import XLSX from 'xlsx'export default {name: 'importExcel',data () {return {tableData: [],}},methods: {beforeUpload (file) {console.log(file, '--文件');this.file2XLSX(file).then((res) => {console.log('可以继续对res数据进行二次处理')this.tableData = res[0].sheet})return false},// excel导入方法file2XLSX (file) {return new Promise(function (resolve, reject) {// 通过FileReader对象读取文件const reader = new FileReader()// 读取为二进制字符串reader.readAsBinaryString(file)reader.onload = function (e) {console.log(e, '读取文件成功的e');// 获取读取文件成功的结果值const data = e.target.result// XLSX.read解析数据,按照type 的类型解析let wb = XLSX.read(data, {type: 'binary' // 二进制})console.log(wb, '---->解析后的数据')// 存储获取到的数据const result = []// 工作表名称的有序列表wb.SheetNames.forEach(sheetName => {result.push({// 工作表名称sheetName: sheetName,// 利用 sheet_to_json 方法将 excel 转成 json 数据sheet: XLSX.utils.sheet_to_json(wb.Sheets[sheetName]) })})resolve(result)}})}},}</script>

三、table导出excel表格

1.导出行数据

2.导出table数据(也会导出合并单元格)

3.导出二维数据的table数据

4.导出合并单元格table数据

<template><div><el-button type="primary" @click="exportSelectData">导出行数据(json_to_sheet)</el-button><el-button type="primary" @click="exportTableData">导出table数据(也会导出合并单元格)(table_to_sheet)</el-button><el-button type="primary" @click="exportTableDataFormAoa">导出二维数据的table数据(aoa_to_sheet)</el-button><el-button type="primary" @click="exportTableDataCellMerging">导出合并单元格table数据(aoa_to_sheet)</el-button><el-table:data="tableData"@selection-change="handleSelectionChange"ref="tableDataRef"id="table1"><el-table-column type="selection" width="55"> </el-table-column><el-table-column prop="date" label="日期" width="180"> </el-table-column><el-table-column prop="name" label="姓名" width="180"> </el-table-column><el-table-column prop="address" label="地址"> </el-table-column></el-table></div></template><script>import XLSX from 'xlsx'export default {name: 'importExcel',data () {return {selectionList: [],tableData: [{date: '-05-02',name: '王小虎',address: '上海市普陀区金沙江路 1518 弄'}, {date: '-05-04',name: '王小虎',address: '上海市普陀区金沙江路 1517 弄'}, {date: '-05-01',name: '王小虎',address: '上海市普陀区金沙江路 1519 弄'}, {date: '-05-03',name: '王小虎',address: '上海市普陀区金沙江路 1516 弄'}]}},methods: {// 获取选择的行数据handleSelectionChange (val) {this.selectionList = val;console.log(this.selectionList, '--行数据');},// 导出选择的行数据exportSelectData () {// 对选择的表格数据处理:添加标题let arr = this.selectionList.map(item => {return {日期: item.date,姓名: item.name,地址: item.address}})// 将json数据变为sheet数据// json_to_sheet: 将一个由对象组成的数组转成sheet;let sheet = XLSX.utils.json_to_sheet(arr)// 新建表格let book = XLSX.utils.book_new()// 在表格中插入一个sheetXLSX.utils.book_append_sheet(book, sheet, "sheet1")// 通过xlsx的writeFile方法将文件写入XLSX.writeFile(book, `user${new Date().getTime()}.xls`)},// 导出table数据exportTableData () {// 获取dom元素(2种方式)// let table1 = document.querySelector("#table1"); // 原生domlet table = this.$refs.tableDataRef.$el// table_to_sheet: 将一个table dom直接转成sheet,会自动识别colspan和rowspan并将其转成对应的单元格合并;let sheet = XLSX.utils.table_to_sheet(table)let book = XLSX.utils.book_new()XLSX.utils.book_append_sheet(book, sheet, "sheet1")XLSX.writeFile(book, `user${new Date().getTime()}.xls`)},// 导出一个二维数组exportTableDataFormAoa () {let aoa = [['姓名', '性别', '年龄', '注册时间'],['张三', '男', 18, new Date()],['李四', '女', 22, new Date()]];// 将一个二维数组转成sheet// aoa_to_sheet: 这个工具类最强大也最实用了,将一个二维数组转成sheet,会自动处理number、string、boolean、date等类型数据;let sheet = XLSX.utils.aoa_to_sheet(aoa);let book = XLSX.utils.book_new()XLSX.utils.book_append_sheet(book, sheet, "sheet1")XLSX.writeFile(book, `user${new Date().getTime()}.xls`)},// 导出合并单元格的table数据exportTableDataCellMerging () {let aoa = [['主要信息', null, null, '其它信息'], // 特别注意合并的地方后面预留2个null['姓名', '性别', '年龄', '注册时间'],['张三', '男', 18, new Date()],['李四', '女', 22, new Date()]];let sheet = XLSX.utils.aoa_to_sheet(aoa);// 设置合并的单元格sheet['!merges'] = [// 设置A1-C1的单元格合并{s: {r: 0, c: 0 }, e: {r: 0, c: 2 } }];let book = XLSX.utils.book_new()XLSX.utils.book_append_sheet(book, sheet, "sheet1")XLSX.writeFile(book, `user${new Date().getTime()}.xls`)}}}</script>

参考

对sheet二次处理的参考:

/tian_i/article/details/84327329

四、table导出excel表格(带样式)

1.导出带样式的excel

<template><div><el-button @click="exportExcel()">导出带样式的excel</el-button></div></template><script>import XLSX from 'xlsx'import XLSXStyle from 'xlsx-style';export default {name: 'exportExcelStyle',methods: {exportExcel () {let data = [['时间', '电压'], ['-12-01 08:57:12', '3.14'], ['-12-01 08:58:20', '3.15']];let titles = ['时间', '电压']var sheet = XLSX.utils.json_to_sheet(data, {skipHeader: true,});/**设置标题头背景色 */for (const key in sheet) {// 第一行,表头if (key.replace(/[^0-9]/ig, '') === '1') {sheet[key].s = {fill: {//背景色fgColor: {rgb: 'C0C0C0' }},font: {//字体name: '宋体',sz: 12,bold: true},border: {//边框bottom: {style: 'thin',color: 'FF000000'}},alignment: {horizontal: 'center' //水平居中}}}// 指定单元格样式if (key === 'A1') {sheet[key].s = {...sheet[key].s,fill: {//背景色fgColor: {rgb: 'E4DFEC' }}}}// 列宽let colsP = titles.map(item => {let obj = {'wch': 25 //列宽}return obj;})sheet['!cols'] = colsP;//列宽// // 每列的列宽// sheet["!cols"] = [{// wpx: 70 //单元格列宽// }, {// wpx: 70// }, {// wpx: 70// }, {// wpx: 70// }, {// wpx: 150// }, {// wpx: 120// }];}let fileName = 'Excel文件.xlsx'let sheetName = 'Excel文件'this.openDownload(this.sheet2blob(sheet, sheetName), fileName);},sheet2blob (sheet, sheetName) {let wb = XLSX.utils.book_new();wb.SheetNames.push(sheetName)wb.Sheets[sheetName] = sheet;// 必须使用xlsx-style才能生成指定样式var wbout = XLSXStyle.write(wb, {bookType: '', bookSST: false, type: 'binary' })var blob = new Blob([s2ab(wbout)], {type: "" }, sheetName);// 字符串转ArrayBufferfunction s2ab (s) {var buf = new ArrayBuffer(s.length);var view = new Uint8Array(buf);for (var i = 0; i != s.length; ++i) view[i] = s.charCodeAt(i) & 0xff;return buf;}return blob;},openDownload (url, saveName) {if (typeof url == "object" && url instanceof Blob) {url = URL.createObjectURL(url); // 创建blob地址}var aLink = document.createElement("a");aLink.href = url;aLink.download = saveName || ""; // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效var event;if (window.MouseEvent) event = new MouseEvent("click");else {event = document.createEvent("MouseEvents");event.initMouseEvent("click",true,false,window,0,0,0,0,0,false,false,false,false,0,null);}aLink.dispatchEvent(event);}},}</script>

2. 结合el-table,根据勾选的内容,导出excel表格

html和css就不写了,主要记录下js功能实现的过程

// 导出函数export async function exportBtn (payloadList) {// payloadList是table表格勾选的内容数组if (payloadList.length === 0) {this.$message({type: 'warning',message: '请选择要导出的记录!'})} else {// 最终生成sheet的aoelistlet finalList = []// 一、准备枚举值// 1.写死let ywlxenum = [{label: '预审选址', value: 'YSXZ' },{label: '土地储备', value: 'TDCBGM' },{label: '农转用报批', value: 'YDBP' },{label: '规划条件', value: 'GHTJ' },{label: '行政划拨', value: 'XZHB' },{label: '公开出让', value: 'GKCR' },{label: '建设用地规划许可', value: 'JSYDGHXK' },{label: '建设工程规划类许可证核发', value: 'JSGCGHXK' },{label: '建设工程竣工规划核实', value: 'JGGHHY' },{label: '竣工验收备案', value: 'JGYSBA' }]// 2.通过请求获取let ydxzenum = []await getEnumByValue({value: 'TDLYXZ' }).then(data => {ydxzenum = mapListFunc(data.fieldEnum)})// 二、通过请求获取数据let resList = [] // 保存请求数据for (let i = 0; i < payloadList.length; i++) {await this.queryInfo({id: payloadList[i].xmguid }).then(res => {// 这里是判断了返回值里还包含了list数组if (res.data.bizGhtjGhqkList.length !== 0) {let bizGhtjGhqkList = res.data.bizGhtjGhqkListbizGhtjGhqkList.forEach(item => {resList.push({...res.data.bizSlsq, ...res.data.bizGhtj, ...item })})} else {resList.push({...res.data.bizSlsq, ...res.data.bizGhtj })}})}// 三、映射关系listlet mappingList = [{field: 'xmmc', value: '项目名称', merge: true }, // merge代表单元格是否合并{field: 'ydxz', value: '用地性质', enum: true, merge: true }, // enum代表是否是枚举值{field: 'dkbh', value: '地块编号' },]// 四、添加标题let titleList = []mappingList.forEach(item => {titleList.push(item.value)})finalList.push(titleList)// 五、添加内容resList.forEach(row => {// 行的listlet ctnList = []let hyfltemp = []let ydxztemp = []mappingList.forEach(item => {if (item.enum) {// 带枚举值的处理switch (item.field) {case 'hyfl':hyfltemp = row[item.field] && row[item.field].split(',')ctnList.push(queryEnumVal(hyflenum, hyfltemp && hyfltemp[(hyfltemp.length - 1)]))breakcase 'ydxz':ydxztemp = row[item.field] && row[item.field].split(',')ctnList.push(queryEnumVal(ydxzenum, ydxztemp && ydxztemp[(ydxztemp.length - 1)]))breakcase 'pzjg':ctnList.push(queryEnumVal(pzjgenum, row[item.field]))breakcase 'ywlx':ctnList.push(queryEnumVal(ywlxenum, row[item.field]))breakcase 'cbywlx':ctnList.push(queryEnumVal(cbywlxenum, row[item.field]))breakdefault:break}} else {// 常规ctnList.push(row[item.field])}})finalList.push(ctnList)})// 六、处理合并单元格let mergeArr = []let {indices } = unipFunc(resList, 'xmguid')mappingList.forEach((item, index) => {if (item.merge) {indices.forEach(itemlist => {if (itemlist.length > 1) {mergeArr.push({s: {r: itemlist[0] + 1, c: index },e: {r: itemlist[itemlist.length - 1] + 1, c: index }})}})}})// 七、生成sheetlet sheet = XLSX.utils.aoa_to_sheet(finalList)// 八、合并单元格和添加样式sheet['!merges'] = mergeArrObject.keys(sheet).forEach((item, index) => {if (sheet[item].t) {sheet[item].s = {// 对齐方式相关样式alignment: {vertical: 'center', // 垂直对齐方式horizontal: 'center' // 水平对齐方式// wrapText: true // 自动换行}}}})// 九、导出excelopenDownloadDialog(sheet2blob(sheet), new Date().getTime() + '.xlsx' || '表名.xlsx')}}function queryEnumVal (enumList, field) {// 获取枚举值对应的keylet enumVal = ''enumList.forEach(item => {if (item.value === field) {enumVal = item.label}})return enumVal}function mapListFunc (params) {// 处理枚举值let list = []list = params.map(item => {item.value = item.enumValueitem.label = item.enumNamereturn item})return list}// 处理数据重复值function unipFunc (list, objKey) {let key = {} // 存储的 key 是type的值,value是在indeces中对应数组的下标let indices = [] // 数组中每一个值是一个数组,数组中的每一个元素是原数组中相同type的下标list.map((item, index) => {// 根据对应字段 分类(type)let itemKey = item[objKey]let _index = key[itemKey]if (_index !== undefined) {indices[_index].push(index)} else {key[itemKey] = indices.lengthindices.push([index])}})// 归类结果let result = []let resultIndex = []indices.map((item) => {item.map((index) => {if (item.length > 1) {result.push(list[index])resultIndex.push(index)}})})return {result, resultIndex, indices }}// 下载excelfunction openDownloadDialog (url, saveName) {if (typeof url === 'object' && url instanceof Blob) {url = URL.createObjectURL(url) // 创建blob地址}var aLink = document.createElement('a')aLink.href = urlaLink.download = saveName || '' // HTML5新增的属性,指定保存文件名,可以不要后缀,注意,file:///模式下不会生效var eventif (window.MouseEvent) event = new MouseEvent('click')else {event = document.createEvent('MouseEvents')event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null)}aLink.dispatchEvent(event)}// 字符串转ArrayBufferfunction s2ab (s) {var buf = new ArrayBuffer(s.length)var view = new Uint8Array(buf)for (var i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFFreturn buf}// 将一个sheet转成最终的excel文件的blob对象,然后利用URL.createObjectURL下载function sheet2blob (sheet, sheetName) {sheetName = sheetName || 'sheet1'let workbook = XLSX.utils.book_new()workbook.SheetNames.push(sheetName)workbook.Sheets[sheetName] = sheet// 生成excel的配置项var wopts = {bookType: 'xlsx', // 要生成的文件类型bookSST: false, // 是否生成Shared String Table,官方解释是,如果开启生成速度会下降,但在低版本IOS设备上有更好的兼容性type: 'binary'}var wbout = XLSXStyle.write(workbook, wopts)var blob = new Blob([s2ab(wbout)], {type: 'application/octet-stream' })return blob}

参考

带样式的导出参考代码:

/weixin_39246975/article/details/121639072别人对xlsx-style的二次封装:

/weixin_51947053/article/details/127370479

五、打印功能

1.直接使用window自带的打印功能: window.print()

<template><div><p>点击下面的按钮,可将页面进行打印</p><div id="printDiv"><p>打印内容 </p><p>打印内容 </p><p>打印内容 </p><p>打印内容 </p></div><button @click="print">打印页面内容</button></div></template><script>export default{methods: {print(){window.print()}}}</script>

2.使用打印插件:vue-print-nb

1、安装 vue-print-nb:

// vue2.x 版本npm install vue-print-nb --save // vue3.x 版本npm install vue3-print-nb --save

2、在项目中引入 vue-print-nb:

// vue2.x版本 -- 全局引入:在项目中入口文件 main.js 文件中全局引入 vue-print-nbimport Vue from 'vue'import Print from 'vue-print-nb'Vue.use(Print)// 局部引入报错,还不知道咋解决,建议是全局引入// vue2.x版本 -- 在需要打印功能的页面引入 vue-print-nbimport print from 'vue-print-nb'export default{directives: {print }}// vue3.x版本 -- 全局引入:在项目中入口文件 main.js 文件中全局引入 vue3-print-nbimport {createApp} from 'vue'import App from './App'import Print from 'vue3-print-nb'const app = createApp(App)app.use(Print)app.mount('#app')// vue3.x版本 -- 在需要打印功能的页面引入 vue3-print-nbimport print from 'vue3-print-nb'export default{directives: {print }}

3、使用 vue-print-nb 实现打印功能

① 实现方式1:打印区域设置id, 打印按钮绑定此 id

<template><div><p>点击下面的按钮,可将div里的内容区域进行打印</p><div id="printDiv"><p>打印内容 </p><p>打印内容 </p><p>打印内容 </p><p>打印内容 </p></div><button v-print="'#printDiv'">打印id为printDiv的div区域内容</button></div></template><script>export default{data(){return{}}}</script>

② 实现方式2:打印区域设置id, 打印按钮进行打印配置

<template><div><p>点击下面的按钮,可将div里的内容区域进行打印</p><div id="printDiv"><p>打印内容 </p><p>打印内容 </p><p>打印内容 </p><p>打印内容 </p></div><button v-print="'printSet'">打印id为printDiv的div区域内容</button></div></template><script>export default{data(){return{printSet: {id: 'printDiv',extraCss: "/ajax/libs/animate.css/4.1.1/pat.css, /ajax/libs/hover.css/2.3.1/css/hover-min.css",extraHead: '<meta http-equiv="Content-Language"content="zh-cn"/>',beforeOpenCallback (vue) {console.log('打开之前')},openCallback (vue) {console.log('执行了打印')},closeCallback (vue) {console.log('关闭了打印工具')}}}}}</script>

③ 打印网址:打印指定url(同一个同源策略)对应的内容

<template><button v-print="'printSet'">打印网址</button></template><script>export default{data(){return{printSet: {url: 'http://localhost:8080/',beforeOpenCallback (vue) {console.log('打开之前')},openCallback (vue) {console.log('执行了打印')},closeCallback (vue) {console.log('关闭了打印工具')}}}}}</script>

④ 打印预览功能

<template><button v-print="'printSet'">打印+预览功能</button></template><script>export default{data(){return{printSet: {url: 'http://localhost:8080/', // 打印网页预览 如果想要打印本地预览,那么可以不用提供url,需提供打印区域的id,例如: id: 'printDiv'preview: true,previewTitle: 'Test Title',previewBeforeOpenCallback (vue) {console.log('正在加载预览窗口')},previewOpenCallback (vue) {console.log('已经加载完预览窗口')},beforeOpenCallback (vue) {console.log('打开之前')},openCallback (vue) {console.log('执行了打印')},closeCallback (vue) {console.log('关闭了打印工具')}}}}}</script>

⑤ 打印异步url

<template><button v-print="'printSet'">打印+预览功能</button></template><script>export default{data(){return{printSet: {asyncUrl (reslove, vue) {setTimeout(() => {reslove('http://localhost:8080/')}, 2000)}, // 异步urlpreview: true,previewTitle: 'Test Title',previewBeforeOpenCallback (vue) {console.log('正在加载预览窗口')},previewOpenCallback (vue) {console.log('已经加载完预览窗口')},beforeOpenCallback (vue) {console.log('打开之前')},openCallback (vue) {console.log('执行了打印')},closeCallback (vue) {console.log('关闭了打印工具')}}}}}</script>

⑥ 实现区域不打印方式

<template><div><div ref="printDiv"><p>打印内容区域</p><p>打印内容区域</p><p>打印内容区域</p><p>打印内容区域</p><p>打印内容区域</p>实现区域不打印方式1:设置class为 no-print 即可实现该区域不打印<p class="no-print">不要打印的内容区域</p>// 实现区域不打印方式2: 自定义不打印区域的class名<p class="do-not-print-div">不要打印的内容区域</p></div> <button @click="printBtnClick">打印按钮</button> </div></template><script>export default{data(){return {}},methods:{printBtnClick(){// 注意必须使用ref指定打印区域,如果通过id或者class,那么wenpack打包后打印区域会为空this.$print(this.$refs.printDiv) // 实现区域不打印方式2this.$print(this.$refs.print, {noPrint: '.do-not-print-div' }) },}}</script>

⑦ vue-print-nb的API配置如下

1、id: String // 范围打印 ID,必填值2、standard: String // 文档类型(仅打印本地范围)3、extraHead: String // <head></head>在节点中添加DOM节点,并用,(Print local range only)分隔多个节点4、extraCss: String // <link>新的 CSS 样式表,并使用,(仅打印本地范围)分隔多个节点5、popTitle: String // <title></title> 标签内容(仅打印局部范围)6、openCallback: Function // 调用打印工具成功回调函数7、closeCallback: Function // 关闭打印工具成功回调函数8、beforeOpenCallback: Function // 调用打印工具前的回调函数9、url: String // 打印指定的 URL。(不允许同时设置ID)10、asyncUrl: Function // 异步网址:通过 'resolve()' 和 Vue 返回 URL11、preview: Boolean // 预览12、previewTitle: String // 预览标题13、previewPrintBtnLabel: String // 预览按钮的名称14、zIndex: String,Number // 预览CSS:z-index15、previewBeforeOpenCallback: Function // 启动预览工具前的回调函数16、previewOpenCallback: Function // 预览工具完全打开后的回调函数17、clickMounted: Function //点击打印按钮的回调函数

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。