VUE使用docxtemplater导出word(带图片) 踩坑 表格循环空格 ,canvas.toDataURL图片失真模糊问题
参考:https://www.codetd.com/article/15219743
- 安装
// 安装 docxtemplater
npm install docxtemplater pizzip --save
// 安装 jszip-utils
npm install jszip-utils --save
// 安装 jszip
npm install jszip --save
// 安装 FileSaver
npm install file-saver --save
// 引入处理图片的插件1
npm install docxtemplater-image-module-free --save
// 引入处理图片的插件2
npm install angular-expressions --save
- 关键代码JS部分
/*** 导出word文档(带图片) doc.js* */
import Docxtemplater from 'docxtemplater'
import PizZip from 'pizzip'
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 = Buffer.from(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;
}export const ExportBriefDataDocx = (tempDocxPath, data, fileName, imgSize) => {console.log(111, tempDocxPath, data, fileName, imgSize)//这里要引入处理图片的插件var ImageModule = require('docxtemplater-image-module-free');var expressions = require('angular-expressions')var assign = require('lodash/assign')var last = require("lodash/last")expressions.filters.lower = function (input) {// This condition should be used to make sure that if your input is// undefined, your output will be undefined as well and will not// throw an errorif (!input) return input// toLowerCase() 方法用于把字符串转换为小写。return input.toLowerCase()}function angularParser(tag) {tag = tag.replace(/^\.$/, 'this').replace(/(’|‘)/g, "'").replace(/(“|”)/g, '"')const expr = expressions.compile(tag)return {get: function (scope, context) {let obj = {}const index = last(context.scopePathItem)const scopeList = context.scopeListconst num = context.numfor (let i = 0, len = num + 1; i < len; i++) {obj = assign(obj, scopeList[i])}//word模板中使用 $index+1 创建递增序号obj = assign(obj, { $index: index })return expr(scope, obj)}}}JSZipUtils.getBinaryContent(tempDocxPath, (error, content) => {if (error) {console.log(error)}expressions.filters.size = function (input, width, height) {return {data: input,size: [width, height],};};let opts = {}opts = {//图像是否居中centered: true};opts.getImage = (chartId) => {//将base64的数据转为ArrayBufferreturn base64DataURLToArrayBuffer(chartId);}opts.getSize = function (img, tagValue, tagName) {//自定义指定图像大小if (imgSize.hasOwnProperty(tagName)) {return imgSize[tagName];} else {return [200, 200];}}// 创建一个JSZip实例,内容为模板的内容 const zip = new PizZip(content)// 创建并加载 Docxtemplater 实例对象// 设置模板变量的值let doc = new Docxtemplater();doc.attachModule(new ImageModule(opts));doc.loadZip(zip);doc.setOptions({parser:angularParser});doc.setData(data)try {// 呈现文档,会将内部所有变量替换成值,doc.render()} catch (error) {const e = {message: error.message,name: error.name,stack: error.stack,properties: error.properties}console.log('err',{ error: e })// 当使用json记录时,此处抛出错误信息throw error}// 生成一个代表Docxtemplater对象的zip文件(不是一个真实的文件,而是在内存中的表示)const out = doc.getZip().generate({type: 'blob',mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'})// 将目标文件对象保存为目标类型的文件,并命名saveAs(out, fileName)})
}/**1. 将图片的url路径转为base64路径2. 可以用await等待Promise的异步返回3. @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;//转成base64let dataurl = canvas.toDataURL("image/" + ext, quality);//返回resolve(dataurl);};})
}
- 导出函数
vue 中引入上述js文件和方法
import {ExportBriefDataDocx,getBase64Sync} from './doc.js'
async ExportBriefDataDocx(){//图片转base64let imgurl= await getBase64Sync('图片路径') let imgurl2= await getBase64Sync('图片路径')let data= {name:this.name,imgurl:this.imgurl,imgurl2:this.imgurl2}let imgSize = {//控制导出的word图片大小,可自定义imgurl:[200, 200],imgurl2:[200, 200],};exportWord("/我的模板.docx", data, `${this.listname}.docx`, imgSize);//docx模板放在public文件夹下,如果是vue2放在static下// ExportBriefDataDocx("/static/我的模板.docx", data, `${listname}.docx`, imgSize);}
- 模板内容
自己准备一个docx文档,然后里面标注好需替换的参数
列表循环-- {#list}{name}{/list}
单个参数–{}
图片–{%imgUrl}

大概就这些,我也是从参考链接里看到的,至此基本能解决大部分问题,但是我还遇到了两个问题,所以自己记录补充一下 - 表格循环打印会多出空格

我想循环表格出来,但是输入数据,出来后实际是这样的
let data= {ld:[{data1:1,data2:2},{data1:1,data2:2}],} ExportBriefDataDocx("/static/wd.docx", data, `${listname}.docx`, imgSize);

多出了很多空格,我想着去掉模板中的换行符,像这样

我本来是想着这样就能少一行,就是正常表格了,但是其实报错了
message: ‘The filetype for this file could not be identified, is this file corrupted ?’, stack: ‘Error: The filetype for this file could not be ide…//./node_modules/jszip-utils/lib/index.js:110:25)’
大概就是类型不对,读不出来什么的
后来灵光一闪,想到参考链接里各种数据都是在表格里的,应该没问题,所以我就想着开始结束都放进去,就像这样

然后结果就对了

7.保存图片模糊问题 quality = 1也没啥用
改成这样,导出后的图片能经得起缩放
export function getBase64Sync(imgUrl,width,height) {
//传入你想要的宽高,最好大一点,这个不会影响导出后的大小,这里的宽高可以理解为分辨率,就是canvas绘制的时候的大小,imgSize里的才是导出到文档的大小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 = width*2; canvas.height = height*2; //宽高放大两倍let context = canvas.getContext("2d");context.drawImage(image, 0, 0); //图片后缀名let ext = image.src.substring(image.src.lastIndexOf(".") + 1).toLowerCase();//图片质量//let quality = 1;//转成base64let dataurl = canvas.toDataURL("image/"+ext);//返回resolve(dataurl);};})
}
相关文章:
VUE使用docxtemplater导出word(带图片) 踩坑 表格循环空格 ,canvas.toDataURL图片失真模糊问题
参考:https://www.codetd.com/article/15219743 安装 // 安装 docxtemplater npm install docxtemplater pizzip --save // 安装 jszip-utils npm install jszip-utils --save // 安装 jszip npm install jszip --save // 安装 FileSaver npm install file-save…...
ubuntu 安装 Pycharm社区版
在Ubuntu中安装pycharm社区版_上玄下纁的博客-CSDN博客 里面可以创建快捷方式,蛮好用的...
IP 监控软件
IP 监控软件可帮助管理员主动监控网络资源。随着各种设备连接到网络,监控设备和接口可能很复杂,为管理员提供这些设备的IP监控,了解其各种性能指标和问题。 使用有效的 IP 监控软件的优势 使用有效的 IP 监控系统和一套全面的 IP 监控工具&…...
C#实现读写CSV文件的方法详解
目录 CSV文件标准 文件示例RFC 4180简化标准读写CSV文件 使用CsvHelper使用自定义方法总结 项目中经常遇到CSV文件的读写需求,其中的难点主要是CSV文件的解析。本文会介绍CsvHelper、TextFieldParser、正则表达式三种解析CSV文件的方法,顺带也会介绍一…...
04 http连接处理(上)
基础知识:epoll、http报文格式、状态码和有限状态机 代码:对服务端处理http请求的全部流程进行简要介绍,然后结合代码对http类及请求接收进行详细分析。 epoll epoll_create函数 #include <sys/epoll.h> int epoll_create(int size)…...
c++(强生成关键字+可变参数模板+emplace)[26]
强制生成 不生成 在C中,可以通过一些方式来控制编译器是否生成某些特殊成员函数(如默认构造函数、拷贝构造函数、拷贝赋值运算符、析构函数等)。 默认生成:如果你没有显式地定义这些特殊成员函数,编译器会自动生成它们…...
Mysql 数据库开发及企业级应用
文章目录 1、Mysql 数据库开发及企业级应用1.1、为什么要使用数据库1.1.1、数据库概念(Database)1.1.2、为什么需要数据库 1.2、程序员为什么要学习数据库1.3、数据库的选择1.3.1、主流数据库简介1.3.2、使用 MySQL 的优势1.3.3、版本选择 1.4、Windows …...
【数据结构】_6.队列
目录 1.概念 2.队列的使用 3.队列模拟实现 4.循环队列 5.双端队列 6.OJ题 6.1 用队列实现栈 6.2 用栈实现队列 1.概念 (1)队列是只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表; (2&am…...
7 网络通信(上)
文章目录 网络通信概述ip地址ip的作用ip地址的分类私有ip 掩码和广播地址 linux 命令(ping ifconfig)查看或配置网卡信息:ifconfig(widows 用ipconfig)测试远程主机连通性:ping路由查看 端口端口是怎样分配的知名端口动态端口 查看…...
MFC图表控件high-speed-charting的使用
high-speed-charting是MFC上的开源图表库,Teechart的替代品。 high-speed-charting的下载地址 https://www.codeproject.com/Articles/14075/High-speed-Charting-Control 特性 High-speed drawing (when axis is fixed) which allows fast plotting of dataUnlimited number …...
Unity中常用方法
1.基础 //初始化引入 [RequireComponent(typeof(BoxCollider2D))] [RequireComponent(typeof(Rigidbody2D))]//游戏帧率设置 60帧Application.targetFrameRate 60;//获取物体对象 //获取到当前物体(根据名称,也可以根据路径)GameObject go GameObject.Find("…...
【监控系统】可视化工具Grafana简介及容器化部署实战
1.什么是Grafana 官网地址:https://grafana.com/ Grafana用Go语言开发的开源数据可视化工具,可以做数据监控和数据统计,带有告警功能。支持快速灵活的客户端图表,面板插件有许多不同方式的可视化指标和日志,官方库中…...
VUE之VueRouter页面跳转
参考资料: 参考视频 参考demo及视频资料 VUE之基本部署及VScode常用插件 VUE之基本组成和使用 VUE之Bootstrap和Element-UI的使用 VUE之axios使用,跨域问题,拦截器添加Token Vue Router官网 Vue Router说明: 说明…...
【188】Java8利用AVL树实现Map
AVL树又被叫做平衡二叉搜索树、平衡二叉树。AVL是其发明者的首字母缩写。 这篇文章中,AVLTreeMap 类集成了 java.util.Map 接口,并利用 AVL 树结构实现了 Map 接口的所有方法。本文还给出了测试代码。 为什么要发明AVL树? 当我按照从小到大…...
[SQL挖掘机] - 右连接: right join
介绍: 右连接是一种多表连接方式,它以右侧的表为基础,并返回满足连接条件的匹配行以及右侧表中的所有行,即使左侧的表中没有匹配的行。右连接将右表的每一行与左表进行比较,并根据连接条件返回结果集。其实, 左连接和右连接原理一…...
bug篇之基于docker安装nacos(2.1.1)使用dubbo连接不上的问题
说明:首先我的nacos安装是2.1.1版本,请注意版本问题。另外启动时用dubbo的话必须先启动服务提供者再启动服务使用者,否则会报错,同时也必须开放三个端口:8848,9848,9849 java.lang.IllegalStat…...
【Python入门系列】第二十一篇:Python物联网和传感器应用
文章目录 前言一、Python在物联网和传感器应用中的优势二、连接传感器和设备三、读取传感器数据四、示例代码和讲解五、进一步处理和分析传感器数据六、更多应用示例1、温湿度监测系统2、智能家居系统 - 灯光控制 总结 前言 物联网和传感器在现代科技中扮演着重要的角色。物联…...
Python爬虫的urlib的学习(学习于b站尚硅谷)
目录 一、页面结构的介绍 1.学习目标 2.为什么要了解页面(html) 3. html中的标签(仅介绍了含表格、无序列表、有序列表、超链接) 4.本节的演示 二、Urllib 1.什么是互联网爬虫? 2.爬虫核心 3.爬虫…...
【MongoDB】--MongoDB聚合Aggregation
目录 一、前言二、聚合管道操作2.1、实际案例1(1)、案例--根据学生no,找到对应班级名称(2)、案例--这个班级有哪些学生和哪些老师在任课 2.2、实际案例2(1)、案例--主表和关联表都有条件限制,且分页返回 一、前言 聚合操作组值来自多个文档,…...
Hadoop学习指南:探索大数据时代的重要组成——Hadoop概述
前言 在当今大数据时代,处理海量数据成为了一项关键任务。Hadoop作为一种开源的分布式计算框架,为大规模数据处理和存储提供了强大的解决方案。本文将介绍Hadoop的组成和其在大数据处理中的重要作用,让我们一同踏上学习Hadoop的旅程。 Hado…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
2025盘古石杯决赛【手机取证】
前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来,实在找不到,希望有大佬教一下我。 还有就会议时间,我感觉不是图片时间,因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看
文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...
【p2p、分布式,区块链笔记 MESH】Bluetooth蓝牙通信 BLE Mesh协议的拓扑结构 定向转发机制
目录 节点的功能承载层(GATT/Adv)局限性: 拓扑关系定向转发机制定向转发意义 CG 节点的功能 节点的功能由节点支持的特性和功能决定。所有节点都能够发送和接收网格消息。节点还可以选择支持一个或多个附加功能,如 Configuration …...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
【WebSocket】SpringBoot项目中使用WebSocket
1. 导入坐标 如果springboot父工程没有加入websocket的起步依赖,添加它的坐标的时候需要带上版本号。 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dep…...
从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
