VUE使用docxtemplater导出word(带图片) 踩坑 表格循环空格 ,canvas.toDataURL图片失真模糊问题

参考:https://www.codetd.com/article/15219743

  1. 安装
// 安装 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
  1. 关键代码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 error
        if (!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.scopeList
                const num = context.num
                for (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的数据转为ArrayBuffer
            return 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;
            //转成base64
            let dataurl = canvas.toDataURL("image/" + ext, quality);
            //返回
            resolve(dataurl);
        };
    })
}
  1. 导出函数
    vue 中引入上述js文件和方法
import {ExportBriefDataDocx,getBase64Sync} from './doc.js'
async ExportBriefDataDocx(){
            //图片转base64
			 let 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);
	      }	
  1. 模板内容
    自己准备一个docx文档,然后里面标注好需替换的参数
    列表循环-- {#list}{name}{/list}
    单个参数–{}
    图片–{%imgUrl}
    在这里插入图片描述
    大概就这些,我也是从参考链接里看到的,至此基本能解决大部分问题,但是我还遇到了两个问题,所以自己记录补充一下
  2. 表格循环打印会多出空格
    在这里插入图片描述
    我想循环表格出来,但是输入数据,出来后实际是这样的
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;
            //转成base64
            let dataurl = canvas.toDataURL("image/"+ext);
           //返回
            resolve(dataurl);
        };
    })
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/52729.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习实践——循环神经网络实践

系列实验 深度学习实践——卷积神经网络实践&#xff1a;裂缝识别 深度学习实践——循环神经网络实践 深度学习实践——模型部署优化实践 深度学习实践——模型推理优化练习 代码可见于&#xff1a; 深度学习实践——循环神经网络实践 0 概况1 架构实现1.1 RNN架构1.1.1 RNN架…

mac版窗口管理 Magnet for mac中文最新

magnet mac版是一款运行在苹果电脑上的一款优秀的窗口大小控制工具&#xff0c;拖拽窗口到屏幕边缘可以自动半屏&#xff0c;全屏或者四分之一屏幕&#xff0c;还可以设定快捷键完成分屏。这款专业的窗口管理工具当您每次将内容从一个应用移动到另一应用时&#xff0c;当您需要…

调整数组顺序使奇数位于偶数前面——剑指 Offer 21

文章目录 题目描述法一 两次遍历法二 双指针一次遍历法三 原地交换 题目描述 法一 两次遍历 class Solution{ public:vectro<int> exchange(vector<int>& nums){vector<int> res;for(auto & num : nums){if(num%21){res.push_back(num);}}for(auto &…

【宝藏系列】STM32之C语言基础知识

【宝藏系列】STM32之C语言基础知识 文章目录 【宝藏系列】STM32之C语言基础知识1️⃣位操作2️⃣define宏定义3️⃣ifdef条件编译4️⃣extern变量声明5️⃣typedef类型别名 C语言是单片机开发中的必备基础知识&#xff0c;本文列举了部分 STM32 学习中比较常见的一些C语言基础知…

Java代码连接RabbitMQ服务器

目录 1.添加依赖 2.生产者代码 3.消费者代码 4.效果 1.发送消息 2.消费消息 5.注意 1.添加依赖 <dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.12.0</version></dependenc…

小研究 - 一种复杂微服务系统异常行为分析与定位算法(二)

针对极端学生化偏差&#xff08;&#xff25;&#xff58;&#xff54;&#xff52;&#xff45;&#xff4d;&#xff45; &#xff33;&#xff54;&#xff55;&#xff44;&#xff45;&#xff4e;&#xff54;&#xff49;&#xff5a;&#xff45;&#xff44; &#…

再下一城丨美格智能座舱模组获头部新势力正式定点

近日&#xff0c;美格智能与国内领先的Tier1厂商密切协作&#xff0c;基于美格车载智能模组打造的智能座舱解决方案&#xff0c;成功获得国内某头部造车新势力的座舱域控制器项目定点&#xff0c;为其打造下一代智能座舱解决方案&#xff0c;创造更加沉浸和智能的座舱体验。 据…

Spring Cloud Alibaba - Nacos源码分析(三)

目录 一、Nacos客户端服务订阅的事件机制 1、监听事件的注册 2、ServiceInfo处理 serviceInfoHolder.processServiceInfo 一、Nacos客户端服务订阅的事件机制 Nacos客户端订阅的核心流程&#xff1a;Nacos客户端通过一个定时任务&#xff0c;每6秒从注册中心获取实例列表&…

测试|测试用例方法篇

测试|测试用例方法篇 文章目录 测试|测试用例方法篇1.测试用例的基本要素&#xff1a;测试环境&#xff0c;操作步骤&#xff0c;测试数据&#xff0c;预期结果…2.测试用例带来的好处3.测试用例的设计思路&#xff0c;设计方法&#xff0c;具体设计方法之间的关系**设计测试用…

企业知识文档管理+群晖nas安全云存储

企业知识管理系统&#xff0c;利用软件系统或其他工具的企业管理方法&#xff0c;利用软件系统或其他工具&#xff0c;对组织中大量的有价值的方案、策划、成果、经验等知识进行分类存储和管理&#xff0c;积累知识资产避免流失&#xff0c;促进知识的学习、共享、培训、再利用…

深蓝学院C++基础与深度解析笔记 第13章 模板

1. 函数模板 ● 使用 template 关键字引入模板&#xff1a; template<typename T> //声明&#xff1a;T模板形参void fun(T); // T 函数形参template<typename T> //定义void fun(T) {...}– 函数模板不是函数 –…

指针进阶详解---C语言

❤博主CSDN:啊苏要学习 ▶专栏分类&#xff1a;C语言◀ C语言的学习&#xff0c;是为我们今后学习其它语言打好基础&#xff0c;C生万物&#xff01; 开始我们的C语言之旅吧&#xff01;✈ 目录 前言&#xff1a; 一.字符指针 二.指针数组 三.数组指针 四.数组、指针参数 …

阿里云服务器全方位介绍_优势_使用_租用费用详解

阿里云服务器全方位介绍包括云服务器ECS优势、云服务器租用价格、云服务器使用场景及限制说明&#xff0c;阿里云服务器网分享云服务器ECS介绍、个人和企业免费试用、云服务器活动、云服务器ECS规格、优势、功能及应用场景详细你说明&#xff1a; 目录 什么是云服务器ECS&…

Games101学习笔记 - 基础数学

向量 向量&#xff1a;方向和长度&#xff0c;没有起始位置 向量长度&#xff1a;各个方向平方相加开方 单位向量&#xff1a;向量除向量的长度 点乘 在笛卡尔坐标系中的点乘计算&#xff1a; 几何意思&#xff1a; 表示一个向量在另一个向量上的投影点乘在图形学中应用&a…

opencv-23 图像几何变换02-翻转-cv2.flip()

在 OpenCV 中&#xff0c;图像的翻转采用函数 cv2.flip()实现 &#xff0c;该函数能够实现图像在水平方向翻转、垂直方向翻转、两个方向同时翻转&#xff0c;其语法结构为&#xff1a; dst cv2.flip( src, flipCode )式中&#xff1a;  dst 代表和原始图像具有同样大小、类…

安卓:JzvdStd——网络视频播放器

目录 一、JzvdStd介绍 JzvdStd的特点和功能&#xff1a; JzvdStd常用方法&#xff1a; 二、JzvdStd使用 1、补充知识&#xff1a; 例子&#xff1a; MainActivity &#xff1a; VideoPageAdapter &#xff1a; activity_main&#xff1a; video_page&#xff1a; …

iOS 应用上架流程详解

iOS 应用上架流程详解 欢迎来到我的博客&#xff0c;今天我将为大家分享 iOS 应用上架的详细流程。在这个数字化时代&#xff0c;移动应用已经成为了人们生活中不可或缺的一部分&#xff0c;而 iOS 平台的 App Store 则是开发者们发布应用的主要渠道之一。因此&#xff0c;了解…

2024考研408-计算机网络 第一章-计算机网络体系结构学习笔记

文章目录 前言一、计算机网络概述1.1、概念及功能1.1.1、计算机网络的概念1.1.2、计算机网络的功能功能1、数据通信功能2、资源共享功能3、分布式处理功能4、提高可靠性&#xff08;分布式处理引申功能&#xff09;功能5、负载均衡&#xff08;也是分布式处理引申功能&#xff…

机器学习的关键词和算法总结

随着全球各行业的数据治理、数字化转型智能化辅助的引入发展&#xff0c;机器学习&#xff08;包括深度学习&#xff09;在逐步深入到各行各业&#xff0c;所以&#xff0c;有必要对机器学习的常见术语&#xff0c;经典算法及应用场景进行一次总结&#xff0c;其实机器学习兴起…

Java Design and development -- QQ chat

About ARTS - Complete one ARTS per week: ● Algorithm: Do at least one LeetCode algorithm per week Review: Read and comment on at least one technical article in English ● Tips: Learn at least one technical trick ● Share: Share a technical article with op…