One, docxtemplater
docxtemplater is a mail merge tool that is used programmatically and handles conditions, loops, and can be extended to insert anything (tables, html, images).
- npm is the easiest way to install docxtemplater
? npm install docxtemplater pizzip --save ?
// install docxtemplater npm install docxtemplater pizzip --save // install jszip-utils npm install jszip-utils --save // install jszip npm install jszip --save // Install FileSaver npm install file-saver --save // Introduce plugin 1 for processing images npm install docxtemplater-image-module-free --save // Introduce plug-in 2 for processing pictures npm install angular-expressions --save
Second, before exporting word, you need to prepare a word template file (according to the style you want to export), and put it in the public folder, as shown below
(here I feel that the grammar used is relatively complete, and there are other grammars that can be exchanged)
Note:
The parts that need to be filled in are defined as variables or json object arrays, the specific format is as follows:
1. Use { } to include a single variable, for example:
{name}, {user}
2. For json array format, wrap a loop object, for example:
The original format is:
list:[ {name:'lipipi'}, {name:'heyaya'} ]
Represented in the template file as:
{#list}{name}{/}
If the object is an image address, you need to add % before the object, for example:
Represented in the template file as:
{#imglist}
{%imgUrl}
{/imglist}
Stamping the pit: I kept reporting the error ‘%imgUrl’ in the picture, and finally found that it must be written in a new line, while other arrays can be written in one line.
3. Package JS
This part is mainly to implement the main implementation method of exporting word documents containing pictures, including converting the url path of pictures to base64 path, converting base64 to binary, and exporting pictures. You can directly copy and paste them into the page for use. The specific code is as follows:
/** * Export word document (with pictures) * */ import Docxtemplater from 'docxtemplater' import PizZip from 'pizzip' import JSZipUtils from 'jszip-utils' import { saveAs } from 'file-saver' /** * Convert data in base64 format to ArrayBuffer * @param {Object} dataURL data in base64 format */ 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) //Here to introduce the plug-in for processing pictures 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 // The toLowerCase() method is used to convert the string to lowercase. 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]) } //Use $index + 1 in the word template to create an incremental serial number 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 = { //Is the image centered? centered: true }; opts.getImage = (chartId) => { //Convert base64 data to ArrayBuffer return base64DataURLToArrayBuffer(chartId); } opts. getSize = function (img, tagValue, tagName) { // Customize the specified image size if (imgSize. hasOwnProperty(tagName)) { return imgSize[tagName]; } else { return [200, 200]; } } // Create a JSZip instance with the content of the template const zip = new PizZip(content) // Create and load Docxtemplater instance object // Set the value of the template variable let doc = new Docxtemplater(); doc. attachModule(new ImageModule(opts)); doc. loadZip(zip); doc.setOptions({parser:angularParser}); doc. setData(data) try { // Rendering the document will replace all internal variables with values, doc. render() } catch (error) { const e = { message: error. message, name: error.name, stack: error. stack, properties: error.properties } console.log('err',{ error: e }) // When using json records, an error message is thrown here throw error } // Generate a zip file representing the Docxtemplater object (not a real file, but an in-memory representation) const out = doc.getZip().generate({ type: 'blob', mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }) // Save the target file object as a file of the target type and name it saveAs(out, fileName) }) } /** * Convert the url path of the picture to the base64 path * You can use await to wait for the asynchronous return of Promise * @param {Object} imgUrl image path */ export function getBase64Sync(imgUrl) { return new Promise(function (resolve, reject) { // Must be set to let, otherwise the picture will not be displayed let image = new Image(); //The map's address image.src = imgUrl; // Solve cross-domain problems image.setAttribute("crossOrigin", '*'); // support cross-origin images // image.onload is asynchronous loading 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); //Picture suffix name let ext = image.src.substring(image.src.lastIndexOf(".") + 1).toLowerCase(); // image quality let quality = 0.8; //Convert to base64 let dataurl = canvas.toDataURL("image/" + ext, quality); //return resolve(dataurl); }; }) }
Fourth, call the export method
<script> import {exportWord,getBase64Sync} from '@/assets/js/outword.js' export default { data () { return { name:'lipipi', listname:'Exported Templates' imglist:[ { imgUrl: "https://img2.baidu.com/it/u=2709954499,581919391 & amp;fm=253 & amp;fmt=auto & amp;app=138 & amp;f=JPEG?w=468 & amp;h=518" }, { imgUrl: "https://img0.baidu.com/it/u=1462004956,1440895436 & amp;fm=253 & amp;fmt=auto & amp;app=138 & amp;f=JPEG?w=500 & amp;h=353" } ] } }, methods: { async exportWordFile(){ //Multiple images traverse to base64 for (let i in this. imglist) { this.imglist[i].imgUrl = await getBase64Sync(this.imglist[i].imgUrl) } let data = { name: this.name imglist:this.imglist } let imgSize = { //Control the size of the exported word image imgurl:[200, 200], }; exportWord("/My template.docx", data, `${this.listname}.docx`, imgSize); } } } </script>