最近有个项目需要实现打印,解决思路是通过html2canvas插件将页面转为图片然后再打印,但是页面中的图片有跨域问题,导致html2canvas生成的图片里的图片不分不显示,
询问过客户图片地址无法做允许跨域处理。既然这样那就只能自己做一个接口来处理图片了。
const contentToPrintDom = document.getElementById('contentToPrint');
const tableRefDom = document.getElementById('tableRef');
if (contentToPrintDom) {
const title = "主标题";
const subTitle = guid.value + "副标题";
const printContainer = document.createElement('div');
printContainer.innerHTML = `
<div style="text-align: center; margin-bottom: 20px;">
<div style="font-size: 24px; font-weight: bold;color:#000">${title}</div>
<div style="font-size: 18px; margin-top: 5px;color:#000">${subTitle}</div>
</div>
`;
contentToPrintDom.insertBefore(printContainer, tableRefDom);
contentToPrintDom.style.height = 'auto';
console.log('打印内容:', contentToPrintDom.innerHTML)
const height = contentToPrintDom.scrollHeight;
try {
const canvas = await html2canvas(contentToPrintDom, {
useCORS: true, // 确保跨域图片可以被捕获
scale: 2, // 高分辨率屏幕适配
windowHeight: height,
height,
});
// 将 canvas 转换为图像数据
const pageData = canvas.toDataURL("image/jpeg", 1.0);
// 创建 jsPDF 实例
const pdf = new jsPDF({
orientation: 'p', // A4 纸张的竖向
unit: 'mm',
format: 'a4',
});
// 计算图像在 PDF 中的尺寸,适应 A4 页面
const imgWidth = 210; // A4 页面宽度(单位:mm)
const imgHeight = (canvas.height * imgWidth) / canvas.width;
// 将图像添加到 PDF 页面
pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight);
// 打印 PDF
pdf.autoPrint(); // 自动启动打印对话框
window.open(pdf.output('bloburl'), '_blank'); // 打开新窗口并触发打印
// const link = document.createElement("a");
// link.href=pageData;
// link.download = '1.png';
// link.click();
contentToPrintDom.style.height = 'calc(100% - 100px)';
contentToPrintDom.removeChild(printContainer);
} catch (error) {
console.error('Error generating PDF:', error);
}
}
服务器node环境
服务器的nodejs是14
nodejs代码
const express = require('express');
const fetch = require('node-fetch');
const app = express();
// 允许跨域的中间件
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*'); // 允许所有域
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
next();
});
// 处理图片的接口
app.get('/fetch-image', async (req, res) => {
const imageUrl = req.query.url; // 从查询参数中获取图片 URL
if (!imageUrl) {
return res.status(400).json({ error: 'Missing image URL' });
}
try {
// 从外部 URL 获取图片
const response = await fetch(imageUrl);
if (!response.ok) {
throw new Error(`Failed to fetch image: ${response.statusText}`);
}
// 获取图片的 MIME 类型
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.startsWith('image/')) {
throw new Error('The URL does not point to a valid image');
}
// 将图片返回给前端
res.set('Content-Type', contentType); // 设置响应头中的 MIME 类型
response.body.pipe(res); // 将图片流直接返回给前端
} catch (error) {
console.error('Error fetching image:', error.message);
res.status(500).json({ error: 'Failed to fetch image' });
}
});
// 启动服务器
const PORT = 8844;
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});
项目依赖
{
"name": "image-proxy",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {
"express": "^4.17.1",
"node-fetch": "^2.6.1"
}
}
实现
接口接收图片地址再返回,这样的图片就可以跨域正常截图操作了。
<div class="listItem" v-for="url in obj.urls.split(',')">
<div class="listItemInner">
<img :src="'http://tupian.wanjunshijie.com/fetch-image?url='+url" alt="">
<div v-for="rect in obj.rectList" class="rect" :style="{
width: rect.width + 'px',
height: rect.height + 'px',
left: rect.left + 'px',
top: rect.top + 'px',
border: rect.show ? '2px solid red' : 'none'
}"></div>
</div>
</div>