这篇文章主要介绍如何使用vue+axios+lrz.js实现微信端图片压缩上传方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!
业务场景
微信端项目是基于Vux + Axios构建的,关于图片上传的业务场景有以下几点需求:
1、单张图片上传(如个人头像,实名认证等业务)
2、多张图片上传(如某类工单记录)
3、上传图片时期望能按指定尺寸压缩处理
4、上传图片可以从相册中选择或者直接拍照
遇到的坑
采用微信JSSDK上传图片
在之前开发的项目中(mui + jquery),有使用过微信JSSDK的接口上传图片,本想应该能快速迁移至此项目。事实证明编程没有简单的事:
1、按指定尺寸压缩图片
JSSDK提供的接口wx.chooseImage 是不能指定图片压缩尺寸的,只能在后端的接口通过localId获取图片时,再转换成指定的尺寸。
2、微信JSSDK的接口权限验证
只要是单页面应用项目,微信JSSDK注入权限验证都会有这个坑,而这个与路由模式(hash 或 history)也有关联。有关此坑, 后续会再次写文总结。参考解决方案 [微信JSSDK] 解决SDK注入权限验证 安卓正常,IOS出现config fail
经过权衡考虑网页可能需要在微信以外的浏览器上也能上传文件,顾后来放弃了采用微信JSSDK接口上传图片的方式。
android版微信,input onchange事件不触发
这个坑,圈内有很多人踩过了。在PC端测试是正常的,发布之后,微信端上传时能选择文件,但之后没有任何效果。日志跟踪,后台的api都未调用,由此判断是input的onchange事件未被触发。
解决方案, 更改input的 accept属性:
<input ref="file" type="file" accept="image/jpeg,image/png" @change="selectImgs" />
将以上代码更改为:
<input ref="file" type="file" accept="image/*" @change="selectImgs" />
如果不允许从相册中选择,只能拍照,增加capture="camera":
<input ref="file" type="file" accept="image/*" capture="camera" @change="selectImgs" />
(注:如果场景支持从相册选择或拍照,测试发现某些机型拍照后返回到了主页。哈哈,也有可能是其他因素引起的问题,未做深究了)
使用Lrz.js压缩图片
目前手机拍照的图片文件大小一般在3-4M,如果在上传时不做压缩处理会相当浪费流量并且占用服务器的存储空间(期望上传原图的另做讨论)。如果能够在前端压缩处理,那肯定是最理想的方案。而 lrz.js 则提供了前端图片文件的压缩方案,并且可以指定尺寸压缩。实测:3M左右的图片文件,按宽度450px尺寸压缩上传后的文件大小在500kb左右,上传时间2s以内。
其核心源码,如下:
selectImgs () { let file = this.$refs.file.files[0] lrz(file, { width: 450, fieldName: 'file' }).then((rst) => { var xhr = new XMLHttpRequest() xhr.open('POST', 'http://xxx.com/upload') xhr.onload = () => { if (xhr.status === 200 || xhr.status === 304) { // 无论后端抛出何种错误,都会走这里 try { // 如果后端跑异常,则能解析成功, 否则解析不成功 let resp = JSON.parse(xhr.responseText) console.log('response: ', resp) } catch (e) { this.imageUrl = xhr.responseText } } } // 添加参数 rst.formData.append('folder', 'wxAvatar') // 保存的文件夹 rst.formData.append('base64', rst.base64) // 触发上传 xhr.send(rst.formData) return rst }) }
单个图片上传组件完整代码,如下(注: icon图标使用的是svg-icon组件):
<template> <div class="imgUploader"> <section v-if="imageUrl" class="file-item "> <img :src="imageUrl" alt=""> <span class="file-remove" @click="remove()">+</span> </section> <section v-else class="file-item"> <div class="add"> <svg-icon v-if="!text" class="icon" icon-class="plus" /> <span v-if="text" class="text">{{text}}</span> <input type="file" accept="image/*" @change="selectImgs" ref="file"> </div> </section> </div> </template> <script> import lrz from 'lrz' export default { props: { text: String, // 压缩尺寸,默认宽度为450px size: { type: Number, default: 450 } }, data () { return { img: { name: '', src: '' }, uploadUrl: 'http://ff-ff.xxx.cn/UploaderV2/Base64FileUpload', imageUrl: '' } }, watch: { imageUrl (val, oldVal) { this.$emit('input', val) }, value (val) { this.imageUrl = val } }, mounted () { this.imageUrl = this.value }, methods: { // 选择图片 selectImgs () { let file = this.$refs.file.files[0] lrz(file, { width: this.size, fieldName: 'file' }).then((rst) => { var xhr = new XMLHttpRequest() xhr.open('POST', this.uploadUrl) xhr.onload = () => { if (xhr.status === 200 || xhr.status === 304) { // 无论后端抛出何种错误,都会走这里 try { // 如果后端跑异常,则能解析成功, 否则解析不成功 let resp = JSON.parse(xhr.responseText) console.log('response: ', resp) } catch (e) { this.imageUrl = xhr.responseText } } } // 添加参数 rst.formData.append('folder', this.folder) // 保存的文件夹 rst.formData.append('base64', rst.base64) // 触发上传 xhr.send(rst.formData) return rst }) }, // 移除图片 remove () { this.imageUrl = '' } } } </script> <style lang="less" scoped> .imgUploader { margin-top: 0.5rem; .file-item { float: left; position: relative; width: 100px; text-align: center; left: 2rem; img { width: 100px; height: 100px; border: 1px solid #ececec; } .file-remove { position: absolute; right: 0px; top: 4px; width: 14px; height: 14px; color: white; cursor: pointer; line-height: 12px; border-radius: 100%; transform: rotate(45deg); background: rgba(0, 0, 0, 0.5); } &:hover .file-remove { display: inline; } .file-name { margin: 0; height: 40px; word-break: break-all; font-size: 14px; overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; } } .add { width: 100px; height: 100px; float: left; text-align: center; line-height: 100px; font-size: 30px; cursor: pointer; border: 1px dashed #40c2da; color: #40c2da; position: relative; background: #ffffff; .icon { font-size: 1.4rem; color: #7dd2d9; vertical-align: -0.25rem; } .text { font-size: 1.2rem; color: #7dd2d9; vertical-align: 0.25rem; } } } input[type="file"] { position: absolute; left: 0; top: 0; width: 100%; height: 100%; border: 1px solid #000; opacity: 0; } </style>
后端图片存储处理
后端api对图片的处理,是必不可少的环节,需要将前端提交过来的base64字符串转换成图片格式,并存放至指定的文件夹,接口返回图片的Url路径。各项目后端对图片的处理逻辑都不一致,以下方案仅供参考(我们使用asp.net MVC 构建了独立的文件存储站点)。
其核心源码,如下:
/// <summary> /// 图片文件base64上传 /// </summary> /// <param name="folder">对应文件夹位置</param> /// <param name="base64">图片文件base64字符串</param> /// <returns></returns> public ActionResult Base64FileUpload(string folder, string base64) { var context = System.Web.HttpContext.Current; context.Response.ClearContent(); // 因为前端调用时,需要做跨域处理 context.Response.AddHeader("Access-Control-Allow-Origin", "*"); context.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); context.Response.AddHeader("Access-Control-Allow-Headers", "content-type"); context.Response.AddHeader("Access-Control-Max-Age", "30"); if (context.Request.HttpMethod.Equals("OPTIONS")) { return Content(""); } var resultStr = base64.Substring(base64.IndexOf(",") + 1);//需要去掉头部信息,这很重要 byte[] bytes = Convert.FromBase64String(resultStr); var fileName = Guid.NewGuid().ToString() + ".png"; if (folder.IsEmpty()) folder = "folder"; //本地上传 string root = string.Format("/Resource/{0}/", folder); string virtualPath = root + fileName; string path = Server.MapPath("~" + virtualPath); //创建文件夹 if (!Directory.Exists(Path.GetDirectoryName(path))) { Directory.CreateDirectory(Path.GetDirectoryName(path)); } System.IO.MemoryStream ms = new System.IO.MemoryStream(bytes);//转换成无法调整大小的MemoryStream对象 System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(ms); bitmap.Save(path, System.Drawing.Imaging.ImageFormat.Png);//保存到服务器路径 ms.Close();//关闭当前流,并释放所有与之关联的资源 return Content(Net.Url + virtualPath); //返回文件路径 }
以上是“如何使用vue+axios+lrz.js实现微信端图片压缩上传方法”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注亿速云行业资讯频道!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。