vue中把页面导出成word文件

思路:先把页面上的元素转成图片,然后把图片放到word文件中进行导出.

1.先下载依赖

sql 复制代码
npm install docxtemplater pizzip  --save

npm install jszip-utils --save 

npm install jszip --save

npm install file-saver --save

npm install docxtemplater-image-module-free --save

npm install angular-expressions --save

npm install html2canvas --save

2.准备word模板

导出word文件需要在项目static文件中先放置一个模板,名称为demo.docx vue2放在static下面,vue3放在public下面

matlab 复制代码
注意:
 
1)模板文件必须是docx文件。doc文件不能通过修改后缀名变为docx,必须另存时选择docx类型,才能实现类型转变。但是docx是可以通过修改后缀名改为doc文件的,因为office的升级基本都是向下兼容的。
 
2)使用英文下的花括号;
 
3)花括号内的键名前后不要有空格,且它与程序中的data对象的键名必须保持一致 ;
 
4)表格中想要循环添加的数据,需要在开头添加{#键名},在结尾处添加{/键名},例如下图的
 
{#table}和{/table};
 
5)图片居中不要使用{%%image2} 

3.封装js,创建一个js文件,其中代码如下:

javascript 复制代码
import PizZip from 'pizzip'
import docxtemplater from 'docxtemplater'
import JSZipUtils from 'jszip-utils'
import {saveAs} from 'file-saver'
 
/**
 * 将base64格式的数据转为ArrayBuffer
 * @param {Object} dataURL base64格式的数据
 */
function base64DataURLToArrayBuffer(dataURL) {
	const base64Regex = /^data:image\/(png|jpg|jpeg|svg|svg\+xml);base64,/;
	if (!base64Regex.test(dataURL)) {
		return false;
	}
	const stringBase64 = dataURL.replace(base64Regex, "");
	let binaryString;
	if (typeof window !== "undefined") {
		binaryString = window.atob(stringBase64);
	} else {
		binaryString = new Buffer(stringBase64, "base64").toString("binary");
	}
	const len = binaryString.length;
	const bytes = new Uint8Array(len);
	for (let i = 0; i < len; i++) {
		const ascii = binaryString.charCodeAt(i);
		bytes[i] = ascii;
	}
	return bytes.buffer;
}
 
/**
 * 导出word,支持图片
 * @param {Object} tempDocxPath 模板文件路径
 * @param {Object} wordData 导出数据
 * @param {Object} fileName 导出文件名
 * @param {Object} imgSize 自定义图片尺寸
 */
export const exportWord = (tempDocxPath, wordData, fileName,imgSize) => {
	//这里要引入处理图片的插件
	var ImageModule = require('docxtemplater-image-module-free');
 
	const expressions = require("angular-expressions");
 
	// 读取并获得模板文件的二进制内容
	JSZipUtils.getBinaryContent(tempDocxPath, function(error, content) {
 
		if (error) {
			throw error;
		}
		expressions.filters.size = function(input, width, height) {
			return {
				data: input,
				size: [width, height],
			};
		};
		function angularParser(tag) {
			const expr = expressions.compile(tag.replace(/'/g, "'"));
			return {
				get(scope) {
					return expr(scope);
				},
			};
		}
		// 图片处理
		let opts = {}
 
		opts = {
			//图像是否居中
			centered: true
		};
		opts.getImage = (chartId) => {
			//console.log(chartId);//base64数据
			//将base64的数据转为ArrayBuffer
			return base64DataURLToArrayBuffer(chartId);
		}
		opts.getSize = function(img, tagValue, tagName) {
			//自定义指定图像大小
			if(imgSize.hasOwnProperty(tagName)){
				return imgSize[tagName];
			}else{
				return [300, 300];
			}
		}
		// 创建一个PizZip实例,内容为模板的内容
		let zip = new PizZip(content);
		// 创建并加载docxtemplater实例对象
		let doc = new docxtemplater();
		doc.attachModule(new ImageModule(opts));
		doc.loadZip(zip);
		doc.setData(wordData);
		try {
			// 用模板变量的值替换所有模板变量
			doc.render();
		} catch (error) {
			// 抛出异常
			let e = {
				message: error.message,
				name: error.name,
				stack: error.stack,
				properties: error.properties
			};
			console.log(JSON.stringify({
				error: e
			}));
			throw error;
		}
		// 生成一个代表docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)
		let out = doc.getZip().generate({
			type: "blob",
			mimeType: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
		});
		// 将目标文件对象保存为目标类型的文件,并命名
		saveAs(out, fileName);
	});
}
 
/**
 * 将图片的url路径转为base64路径
 * 可以用await等待Promise的异步返回
 * @param {Object} imgUrl 图片路径
 */
export function getBase64Sync(imgUrl) {	
	return new Promise(function(resolve, reject) {
		// 一定要设置为let,不然图片不显示
		let image = new Image();
		//图片地址
		image.src = imgUrl;
		// 解决跨域问题
		image.setAttribute("crossOrigin", '*');  // 支持跨域图片
		// image.onload为异步加载
		image.onload = function() {
			let canvas = document.createElement("canvas");
			canvas.width = image.width;
			canvas.height = image.height;
			let context = canvas.getContext("2d");
			context.drawImage(image, 0, 0, image.width, image.height);
			//图片后缀名
			let ext = image.src.substring(image.src.lastIndexOf(".") + 1).toLowerCase();
			//图片质量
			let quality = 0.8;
			//转成base64
			let dataurl = canvas.toDataURL("image/" + ext, quality);
			//返回
			resolve(dataurl);
		};
	})
}

4.vue文件使用

xml 复制代码
<template>
	<el-container class="a-section xxx">
		<el-button type="success" @click="download">导出导出</el-button>
		<div class="canvasBox">
			测试文件内容展示
			<el-progress :text-inside="true" :stroke-width="26" :percentage="70"></el-progress>
			<el-progress :text-inside="true" :stroke-width="24" :percentage="100" status="success"></el-progress>
			<el-progress :text-inside="true" :stroke-width="22" :percentage="80" status="warning"></el-progress>
			<el-progress :text-inside="true" :stroke-width="20" :percentage="50" status="exception"></el-progress>
		</div>
	</el-container>
</template>
<script>
//刚刚创建的js文件
import { exportWord, getBase64Sync } from 'xxxx.js'
import html2canvas from 'html2canvas';
export default {
	name: 'xxx',
	mounted() {
	},
	methods: {
		async download() {
            // 找到需要导出的元素
			var oTd = document.querySelector('.canvasBox');

            //使用html2canvas生成base64的图片格式
			html2canvas(oTd, {
				width: Math.floor(oTd.clientWidth), //宽
				height: Math.floor(oTd.clientHeight), //高
				scale: 2,  //设置像素比
				useCORS: true,
				allowTaint: false,
			}).then((canvas) => {
				document.body.appendChild(canvas);
				var img = document.createElement('img');
				//获取图片路径 并且转base64格式
				img.src = canvas.toDataURL('image/jpeg');
				console.log(img.src, "路径");
				var dataURL = img.src
				console.log(dataURL, 'base64格式');
				img.setAttribute('id', 'canvasImg');
				let data = {
					imglist: this.imglist,
					imgUrl: dataURL
				}
				let imgSize = {
					//控制导出的word图片大小
					imgurl: [200, 200],
				};
				//导出的文件名称
				let docxName = "测试使用.docx";
				exportWord("/static/demo.docx", data, docxName, imgSize);
			})
		},
	}
}
</script>
<style>
</style>

结果展示

感谢脚本之家作者"薇森"的vue实现导出word文档功能实例(含多张图片)提供思路.谢谢.

相关推荐
狸克先生3 分钟前
如何用AI写小说(二):Gradio 超简单的网页前端交互
前端·人工智能·chatgpt·交互
baiduopenmap18 分钟前
百度世界2024精选公开课:基于地图智能体的导航出行AI应用创新实践
前端·人工智能·百度地图
loooseFish25 分钟前
小程序webview我爱死你了 小程序webview和H5通讯
前端
请叫我欧皇i38 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
533_40 分钟前
[vue] 深拷贝 lodash cloneDeep
前端·javascript·vue.js
guokanglun1 小时前
空间数据存储格式GeoJSON
前端
zhang-zan1 小时前
nodejs操作selenium-webdriver
前端·javascript·selenium
猫爪笔记1 小时前
前端:HTML (学习笔记)【2】
前端·笔记·学习·html
brief of gali2 小时前
记录一个奇怪的前端布局现象
前端
Json_181790144803 小时前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库