背景
结合后端数据生成运营推广页面,用户通过保存操作将推广页面保存为图片进行分享和传播。其中涉及到的前端主要技术点:
dom转图片- 保存图片到本地
了解 CORS
CORS(Cross-Origin Resource Sharing,跨域资源共享),同源安全策略默认阻止跨域获取资源,通过CORS给了Web服务器这样的权限,即服务器可以选择,允许跨域请求访问到它们的资源。CORS由一系列传输的HTTP头组成,这些HTTP头决定浏览器是否阻止前端JavaScript代码获取跨域请求的响应。
什么情况下需要CORS:
- 由
XMLHttpRequest或Fetch发起的跨源HTTP请求。 Web字体 (CSS中通过@font-face使用跨源字体资源)。WebGL贴图。- 使用
drawImage将Images/video画面绘制到canvas。
技术方案
html2canvas提供将dom绘制到canvas,file-saver:提供将Blob导出为本地文件。流程既是:
dom => html2canvas => canvas => blob => file-saver => image
import html2canvas from 'html2canvas';
import { saveAs } from 'file-saver';
const dom = document.getElementById('html-to-canvas')
html2canvas(dom, {
useCORS: true,
})
then(canvas => {
const blob = canvas.toBlob((blod: Blob | null) => {
if (blob) {
saveAs(blob, 'html2canvas.png')
}
})
})
问题与方案
跨域
由于canvas对于图片资源的同源限制,如果画布中包含跨域的图片资源则会污染画布,如上对于CORS介绍中用讲到使用drawImage将Images/video画面绘制到canvas需要配合CORS使用。可以通过配置useCORS: true,且img标签配置crossOrigin = 'anonymous'支持CORS。
资源加载不全
图片资源在生成快照是还未完全加载,造成快照内容不全,通过Promise.all保证图片资源加载完成,并开启快照生成功能。
// 加载图片
const toBlobURL = (url: string) => {
return new Promise((resolve, reject) => {
const canvasDom = window.document.createElement('canvas')
const ctx = canvasDom.getContext('2d')
const img = window.document.createElement('img')
img.crossOrigin = 'anonymous'
img.src = url
img.onload = () => {
canvasDom.width = img.width
canvasDom.height = img.height
ctx!.drawImage(img, 0, 0)
canvasDom.toBlob((blob: Blob | null) => {
if (blob) {
const blobURL = URL.createObjectURL(blob)
resolve(blobURL)
} else {
reject()
}
})
}
img.onerror = () => {
reject()
}
})
}
// 加载内容
const imgLists = imgContainerDom.querySelectorAll('img')
Promise.all(
Array.from(imgLists).map((imgDom, i) => {
return toBlobURL(imgDom.src)
}),
)
.then(res => {
for (let i = 0; i < imgLists.length; i++) {
imgLists[i].src = (res as any)[i]
}
})
.catch((e) => {
console.log('enter error handle')
console.log(e)
})
微信导出不成功
issues:github.com/niklasvh/ht…
建议使用"html2canvas": "1.0.0-rc.4"