大家好,我是南游。
最近遇到了使用canvas绘制分享海报的需求,在这里对开发过程中遇到的一些问题进行了整理。
1.图片的绘制是异步的,要在图片上进行内容绘制需要在背景图片绘制完成后进行绘制,即在回调里面执行。
scss
img.onload = () => {
ctx.drawImage(img, 0, 0)
//do something
}
2.海报绘制完成时保存下载图片报错(跨域)的问题。
ini
<div className="poster-wrap">
<canvas className="canvas" id="canvas" width="375" height="820" > </canvas>
</div>
如果使用跨域的资源画到canvas中,并且资源没有使用CORS去请求,canvas会被认为是被污染了, canvas可以正常展示,但是没办法使用[toDataURL()
]或者[toBlob()
])导出数据。
详情见 Allowing cross-origin use of images and canvas
因此需要在img标签上设置crossorigin
,启用CORS,属性值为anonymous
ini
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
const img = new Image()
img.crossOrigin = 'anonymous'
img.src = 'xxxxxxx'
img.onload = () => {
ctx.drawImage(img, 0, 0)
}
添加crossOrigin="anonymous"允许跨域后图片却无法显示了,依然报错跨域,此时需要在服务端配置跨域设置
因为我的图片是放在阿里云上的,因此需要在阿里云的oss跨域设置里进行配置,允许 *.test.com
跨域。详情见
设置成功后可以在f12上看请求静态资源的响应头,如果响应头里面带了Access-Control-Allow-Origin域名,那么浏览器就允许跨域访问。
图片已经通过img标签加载过,浏览器默认会缓存下来,下次使用js方式再去请求,直接返回缓存的图片,如果缓存中的图片不是通过CORS请求或者响应头中不存在Access-Control-Allow-Origin
,都会导致报错。使用js方式请求图片资源, 需要避免使用缓存,设置url后加上时间戳,或者http头设置Cache-Control为no-cache。
ini
let img = new Image()
img.crossOrigin = 'anonymous'
img.src = url + '?time=' + new Date().valueOf()
img.onload = () => {
// ... do something
}
img.onerror = (err) => {
console.log(err)
}
最后就是根据需求画好海报并下载。
ini
ctx.fillStyle = '#ffffff'
ctx.font = 'bold 20px sans-serif'
ctx.fillText('hello world', 15, 24)
ctx.font = 'bold 10px sans-serif'
ctx.fillText('hello', 30, 24)
javascript
function downloadPoster() {
let imgSrc = canvas.toDataURL('image/png', 0.9)
let imgName = '海报'
let elem = document.createElement('a')
elem.setAttribute('href', imgSrc)
elem.setAttribute('download', imgName)
document.body.appendChild(elem)
elem.click()
document.body.removeChild(elem)
}