一、背景
同一个网页,canvas在PC端可以右键下载,但是在移动端长按时却没反应。现在要求在移动端支持长按图片下载
二、实现方式
画布(canvas)对象有一个非常有用的方法toDataURL(),
这个方法能把画布里的图案转变成base64编码格式的png,然后返回Data URL数据。利用这个我们可以将转成一个image/png格式的图片
// 获取所有的canvas图片文件
let canvasDom = document.getElementsByTagName('canvas')
for(let i=0;i<canvasDom.length;i++){
generateImg(canvasDom[i])
}
// 获取图片的相对位置,注意这里应该是相对位置
function getImgRelativePosition(element){
let actualLeft = element.offsetLeft;
let actualTop = element.offsetTop;
let current = element.offsetParent;
while (current !== null){
actualLeft += current.offsetLeft;
actualTop += current.offsetTop;
current = current.offsetParent;
}
return{
actualLeft:parseInt(actualLeft - element.target.scrollLeft) + 'px',
actualTop:parseInt(actualTop - element.target.scrollTop) + 'px',
}
},
// 在每一个canvas上生成image图片,这样在移动端就可以支持长按下载了
function generateImg(element){
let relativePosition = this.getImgRelativePosition(element)
let dataImg = new Image()
let imgWidth = element.scrollWidth + 'px'
let imgHeight = element.scrollHeight + 'px'
dataImg.src = element.toDataURL('image/png')
dataImg.style.cssText =
`width:${imgWidth};height:${imgHeight};position:absolute;top:
${relativePosition.top};left:${relativePosition.left};opacity:0;`;
document.body.appendChild(dataImg)
},
三、开发过程中的踩坑
- 参考的网友的思路,地址在https://juejin.im/post/6844903861866463239,该网友没有获取图片的位置,将canvas转成的img覆盖在了整个body上,对其它图片进行长按操作时,实际上是在第一个canvs转成的img上进行的操作,之后下载的都是第一张图,所以我治理获取了图片的定位,在该图上进行img图片的覆盖,这样就避免了这个问题
- 该网友的思路是在长按时将img覆盖到body上,利用img长按在移动端可以保存的原理,在实践过程中会发现,第一次长按时没有出现保存图片的菜单,是因为第一次长按之后才有覆盖img,所以第二次长按才能够正常保存,这个是不能忍受的,所以我的做法只在图片onload之后就将img图片覆盖在上面
- 在第二点基础上,如果覆盖了img之后保存了图片之后发现图片是空的,可以去html里检查一下这个图是不是透明的,如果是那就是你的图片还没有加载出来你就将img图片覆盖了,所以这时候要确保图片加载完成后再将img覆盖上去