微信小程序H5保存图片到相册

190 阅读3分钟

方案一 使用HTML5的download属性

浏览器里,如果有点击下载图片的需求,可以使用download属性,如:

一键获取完整项目代码 但在使用前,需要考虑下两个问题:跨域问题和兼容问题。

1.跨域问题

download只对同源资源有效。MDN上关于这一点有说明,详见:

<a>: The Anchor element​developer.mozilla.org

想解决这个问题,也比较简单,搭个代理转发一下即可。

2.兼容性问题

caniuse上显示的download属性兼容情况如下:

图中显示QQ浏览器是不支持的,而微信内置的浏览器和QQ浏览器使用的是一样的内核,即X5内核,那基本可推断出微信也是不支持download属性的。

但我又有一点不甘心,决定亲自实践看是否支持download属性。

var hasDownloadAttribute = 'download' in document.createElement('a') 一键获取完整项目代码 将该脚本加在网页里,并在微信环境打开,运行结果居然是"true"。

只有两种推论:

1)当前设备的微信内置浏览器不是X5内核

2)当前设备微信内置浏览器是X5内核,微信已经开始支持download属性了。

那怎么验证当前设备微信内置浏览器是不是X5内核呢?在微信里打开

X5内核调试专用页​debugx5.qq.com ,结果显示当前设备的微信内置浏览器不是X5内核。嗯,能解释得通了。

而我当前设备上的微信内置浏览器是什么呢?通过navigator.userAgent查看,当前设备上的微信内置的浏览器是Chrome 78.0,内核是Blink。

但是不是应用了download属性就可以实现微信H5点击图片下载了?

太天真。抛开兼容性问题,实践下来,还是无法实现点击保存图片。保存图片需要系统相册的权限,只能由app本身来做,不论你是Webview还是微信内置浏览器的网页,如果没有跟微信通信,调用app本身保存图片的能力,无法实现点击保存图片。

方案二 使用download.js

download兼容性不好是吧?那我用第三方库download.js可以了吧?

rndme/download​github.com 示例代码如下:

import axios from 'axios';
import download from 'downloadjs';
axios.get(someUrl, { responseType: 'blob'}).then(res => {
  download(res.data, "awesome.png", "image/png");
})

一键获取完整项目代码 先讲结论,同方案1一样,只是解决了兼容性问题,但无法调起微信app保存图片的能力。

不work没关系,可以顺便来看看download.js怎么兼容的。

download.js的源码,我浓缩了一下,用伪代码表示是这样。

const saver = (url, mimeType) => {
  // 如果支持download属性
  if ('download' in anchor) {
   anchor.href = url;
   anchor.style.display = 'none';
   document.body.appendChild(anchor);
   setTimeout(() => {
     anchor.click();
     document.body.removeChild(anchor);
     setTimeout(() => {
      // 释放通过createObjectURL创建的URL
       window.URL.revokeObjectUrl(blob);
     }, 250)
   }, 100)
   return;
  } 
  
  // 兼容不支持download属性的部分Safari浏览器
  if (/(Version)/(d+).(d+)(?:.(d+))?.*Safari//.test(navigator.userAgent)) {
    if (/^data:/.test(url) { url = 'data:' + url.replace(/^data:([w/-+]+)/, defaultMime) }
    if (!window.open(url)) { 
      location.href = url;
    }
    return
  }
 
  // 利用iframe来实现下载。需要注意的是,如果浏览器支持预览该文件格式,则不能实现下载。
  const f = document.createElement('iframe');
  document.body.appendChild(f);
  f.src = url;
  setTimeout(() => {
    document.body.removeChild(f);
  }, 300)
}
 
// Case 1: 如果支持Blob和URL
if (window.URL) {
  // 创建指向blob对象的URL
  const url = window.URL.createObjectURL(blob);
  saver(url);
  return;
}
 
// Case 2: 如果支持Blob和msSaveBlob,但不支持URL。
if (navigator.msSaveBlob) {
  navigator.msSaveBlob(dataUrlToBlob(payload), filename);
  return;
} 
 
// Case 3: 如果支持Blob,但不支持URL和msSaveBlob
// 将blob转成base64编码的数据
const reader = new FileReader()
reader.readAsDataURL(blob)
reader.onloadend = function () {
  const base64data = reader.result
  saver(base64data);
}
 
// Case 4: 如果Blob和URL都不支持
if (!window.Blob && !window.URL) {
  const base64Data = window.btoa(blob);
  const url = `data:${mimeType};base64,${base64Data}`; 
  saver(url);
}

参考:

微信小程序实现一键长图并保存图片到相册

微信小程序webview保存图片

a href点击无效_从微信H5点击保存图片说起