微信H5里保存图片,大都是通过长按操作,弹起actionsheet保存照片。但我们的部分用户是老年群体,不知道怎么进行“长按”操作。考虑到这个因素,产品要求实现点击保存按钮来保存图片。

不难想,你会立马蹦出这几个方案:

方案一 使用HTML5的download属性

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

<a href="me.png" download="me"></a>

但在使用前,需要考虑下两个问题:跨域问题和兼容问题。

1.跨域问题

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

<a>: The Anchor element​developer.mozilla.org/en-US/docs/Web/HTML/Element/a正在上传…重新上传取消

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

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/rndme/download

示例代码如下:

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创建的URLwindow.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对象的URLconst 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.resultsaver(base64data);
}// Case 4: 如果Blob和URL都不支持
if (!window.Blob && !window.URL) {const base64Data = window.btoa(blob);const url = `data:${mimeType};base64,${base64Data}`; saver(url);
}

上面有个比较关键的函数:dataUrlToBlob。它主要是将dataUrl转成Blob对象,保证msSaveBlob接收的参数是Blob对象实例。

function dataUrlToBlob (strUrl) {const parts = strUrl.split(/[:;,]/)const type = parts[1]const indexDecoder = strUrl.indexOf('charset') > 0 ? 3 : 2// 如果字符串是base64编码,解码方法使用atob;否则使用decodeURIComponent。const decoder = parts[indexDecoder] == 'base64' ? atob : decodeURIComponent// 解码const binData = decoder(parts.pop())const mx = binData.lengthlet i = 0// 创建数组长度为mx的数组,其中数组元素都是0const uiArr = new Uint8Array(mx)// 将解码后的数据进行unicode编码for (i; i < mx; ++i) { uiArr[i] = binData.charCodeAt(i) }return new Blob([uiArr], { type })
}

总结一下就是:先看是否支持Blob和URL,再看是否支持download属性。

虽然方案二是不work的,但解决浏览器里H5相关资源的下载可以使用download.js。

方案三 使用微信js-sdk

方案一和方案二不能下载图片的原因,都在于没有与原生app进行通信,调用原生app下载图片的能力。那引入微信的js-sdk总可以了吧?

先说结论,就该应用场景来说,不支持。

需要下载的图片资源来源于管理系统后台,而不是用户。

而微信js-sdk需要用户先从本地系统相册上传图片到微信图片服务器,才能从图片服务器下载图片到本地。文档如下:

概述 | 微信开放文档​developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#20

文档里也有说明,上传图片的有效期是3天,所以为了长期为用户提供下载服务,还需要下载图片到自己的服务器上。下载图片需要前后调用三个API:wx.chooseImage、wx.uploadImage和wx.downloadImage。

wx.chooseImage({count: 1, // 默认9sizeType: ['original'],sourceType: ['album', 'camera'],success (res) {const localId = res.localIds[0]// 选择图片成功,上传到微信图片服务器wx.uploadImage({localId, // 需要上传的图片的本地ID,由chooseImage接口获得isShowProgressTips: 1, // 默认为1,显示进度提示success (res) {const serverId = res.serverId // 返回图片的服务器端IDwx.downloadImage({serverId, // 需要下载的图片的服务器端ID,由uploadImage接口获得isShowProgressTips: 1, // 默认为1,显示进度提示success (res) {this.localId = res.localId}})}})}
})

方案四 js手动实现长按事件,唤起actionsheet

已知的是用户长按图片,能唤起actionsheet,那肯定app和微信H5之间是有通信的,对touchstart和touchend事件有监听。那既然点击事件无法唤起微信保存图片的actionsheet,我能不能用js模拟用户,手动实现长按事件呢?

onClick的回调里绑定longPress函数。

function longPress () {const target = document.getElementById('share-img')const startEvent = createTouchEvent(target, 'touchstart')target.dispatchEvent(startEvent)// 5s后触发touchendsetTimeout(() => {const endEvent = createTouchEvent(target, 'touchend')target.dispatchEvent(endEvent)}, 5000)
}function createTouchEvent (touchTarget, type) {const event = document.createEvent('UIEvent')event.initUIEvent(type, true, true, window, 1)const touches = [{ target: touchTarget }]Object.defineProperties(event, {changedTouches: { value: touches }})return event
}

实践下来,虽然能模拟长按事件,但无法唤起actionsheet。究其原因,应该是原生微信app顶层layer对用户的长按手势有监听。所以无论js里怎么模拟长按事件,永远不是用户的手势操作,也无法触发长按手势回调,唤起actionsheet。

微信里应该也对UIWebview加了longPress的gesture recognizer。就iOS而言,伪代码如下:

NSString *imgURL = [NSString stringWithFormat:@"document.elementFromPoint(%f, %f).src", touchPoint.x, touchPoint.y];
NSString *urlToSave = [self.webView stringByEvaluatingJavaScriptFromString:imgURL];
UILongPressGestureRecognizer* longPressed = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressed:)];
longPressed.delegate = self;
[self.webView addGestureRecognizer:longPressed];

但微信H5里长按保存图片,不止是顶层layer长按gensture的监听,也涉及到app与webview的通信。比如,app里可能会inject这段脚本到webview里进行长按事件的监听。

可以比较肯定的是,微信注入的脚本里,addEventListener的第三个参数useCapture option一定是设置成了true。因为touchstart回调里如果调用了event.preventDefault(),长按图片是无法唤起保存图片的actionsheet。

let startTime = 0;
document.addEventListner('touchstart', function() {startTime = Date.now();
}, true)document.addEventListener('touchend', function() {const endTime = Date.now();if (endTime - startTime > 3000) {// dispatchLongTimeEvent();}
}, true)

终上,我无法解决如何在微信H5里点击保存图片。

如果H5仅仅是微信内置浏览器打开的网页,就需要微信提供相应的API支持;

如果H5是微信小程序打开的webview,需要webview和微信小程序可以通信,并调用微信小程序下载图片的API。

转载于:https://zhuanlan.zhihu.com/p/260941705

从微信H5点击保存图片说起-微信图片下载相关推荐

  1. h5页面保存img_从微信H5点击保存图片说起

    微信H5里保存图片,大都是通过长按操作,弹起actionsheet保存照片.但我们的部分用户是老年群体,不知道怎么进行"长按"操作.考虑到这个因素,产品要求实现点击保存按钮来保存图 ...

  2. 微信h5页面跳转浏览器 在微信中点击链接直接跳转到手机默认浏览器代码实现

    现如今微信对第三方推广链接的审核是越来越严格了,域名在微信中分享转发经常会被拦截,一旦被拦截用户就只能复制链接手动打开浏览器粘贴才能访问,要不然就是换个域名再推,周而复始.无论是哪一种情况都会面临一个 ...

  3. 微信h5更新服务器 用户不更新,微信网页授权token刷新和缓存问题

    业务场景: 目前有一个微信公众号,里面有好几个菜单,点击菜单的时候会跳转到业务页面,业务页面会去通过网页获取accesstoken的方式获取用户信息. 我们知道,微信提供了标准的oauth2.0的规范 ...

  4. 安卓手机微信H5中无法长按保存base64图片、blob形式图片的解决办法

    解决实现安卓[微信]H5长按无法保存和分享base64图片问题 问题产生原因,后台发来图片的base64编码有中有空格存在,而ios的WebView可以自动做处理,android则不能. **解决方法 ...

  5. 实现[微信]H5长按保存图片功能

    通过js插件html2canvas实现 a.下载html2canvas.js(github地址:https://github.com/niklasvh/html2canvas/releases/.官网 ...

  6. android仿微信头像点击放大查看,仿微信查看图片(带大小图切换查看)

    之前一直想仿微信朋友圈那样做个图片查看,但是看了网上很多demo都觉得比较简单,少了从小图切换到大图的加载过程,都只是在所有预览里加载大图,点击进去也是加载大图,于是在网上下载了别人的demo自己修改 ...

  7. android 微信登录点击没翻译,[android] 微信登录,没有唤起微信,直接返回ERR_AUTH_DENIED...

    我遇到了类似的问题,第一次能够唤起微信,之后就唤起不了 Permission Denial: receiving Intent { act=com.tencent.mm.plugin.openapi. ...

  8. 微信h5游戏域名该怎么在微信中做好防封防屏蔽技术

    微信屏蔽网页的依据是什么? 明面上的原因是网页内容有诱导.诈骗等不和谐的内容时候,被用户举报就会封闭.实际上这只是表面现象,因为我们能明确的感受到不同的阶段,同样的内容,被封杀的频率差别很大的,也就是 ...

  9. 微信h5棋牌类APP如何在微信中做好防封防屏蔽技术

    为什么关心这种技术?因为我经常听到身边搞微商.搞微信项目的朋友都在叫苦连天,由于微信域名屏蔽.微信域名被拦截.弄得他们尸横遍野,损失的连过年回家的路费都没了,曾经的叱咤风云一下变成了今日的倒亏损.腾讯 ...

  10. H5分享h5页面、小程序到微信

    1.H5分享h5页面(卡片链接形式)到微信 先去微信公众平台填写js接口安全域名 本来想用微信开发js-sdk的,但是做了半天好像没啥效果 概述 | 微信开放文档 (qq.com) 引入js文件:ht ...

最新文章

  1. 史上最详细的微生物扩增子数据库整理
  2. mft按钮设计_奥林巴斯M4/3系统新品激情再燃 以轻量化设计铸就微单极致体验
  3. SharePoint 2013: The New Web Application button is disabled is the central administration
  4. synchronized锁的基本用法
  5. memcached 安装小结-1
  6. 设置一个双色球脚本(2)并带颜色输出
  7. leetcode------Word Search
  8. Linux程序实现弹框,jQuery实现弹出框 效果绝对美观
  9. 30万总奖金·垃圾分类挑战赛进入最后冲刺(附baseline完整分享)
  10. System.getProperty(user.dir) 获取jar包所在目录
  11. 继京东27亿买饭店之后 头条要花90亿买广场?张一鸣曾表示年轻人应住市区
  12. 大学计算机文档基本操作实验的效果,上海工程技术大学计算机实验报告5
  13. 第五章 APP元素定位
  14. 迅捷pdf虚拟打印机怎么安装使用
  15. SEGGER Embedded Studio 缺少 mergehex工具
  16. DHT磁力链数据爬取和资源搜索站的搭建
  17. 安装Win7系统,提示缺少所需的CD/DVD驱动器设备驱动程序
  18. iOS开发:上架的App生成二维码下载的方法
  19. PyCharm搜索技巧快捷键
  20. Excel导入导出功能

热门文章

  1. 语音处理:霍夫曼编码算法原理分析
  2. python自学篇——PyGame模块的所有功能函数详解
  3. Linux系统扩容硬盘
  4. 手把手:用OpenCV亲手给小扎、Musk等科技大佬们做一张“平均脸”(附Python代码)
  5. 牛!发出中国第一封电子邮件,注册登记域名CN,中国互联网之父传奇
  6. 珠海市世鸿置业有限公司5周年线下交流会带你学会用基金理财
  7. 5款在线制图工具分享,快来看看!
  8. matlab怎么通分,matlab常见符号运算( 因式分解、展开、合并、简化及通分等,计算导数,积分,符号求和、代数方程和微分方程求解)...
  9. 46泰勒中值定理的常规证明
  10. 怎么使用JavaScript进行进制…