uniapp 使用uView框架 upload组件上传前压缩图片

您所在的位置:网站首页 图片压缩图片 uniapp 使用uView框架 upload组件上传前压缩图片

uniapp 使用uView框架 upload组件上传前压缩图片

#uniapp 使用uView框架 upload组件上传前压缩图片| 来源: 网络整理| 查看: 265

根据Uview官方文档所说,若是小程序和app项目,上传使用压缩图片,可以配置u-upload组件的sizeType属性为'compress',但这对H5是无效的。在实际开发中,图片压缩上传经常是一个必要的需求,所以本篇文章主要讲的是在H5项目中如何使用Uview的upload组件进行压缩图片。

 首先在utils中封装压缩图片的方法:

tool.js

/** * 图片压缩 * imgSrc 地址 * scale 压缩质量 0-1 * type 文件类型 */ const compressImg = (imgSrc, scale, type, callback) => { // uni.$u.toast('压缩中') var img = new Image(); img.src = imgSrc; img.onload = function() { var that = this; var h = (img.height * scale).toFixed(0); // 默认按质量比例压缩 var w = (img.width * scale).toFixed(0); var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var width = document.createAttribute("width"); width.nodeValue = w; var height = document.createAttribute("height"); height.nodeValue = h; canvas.setAttributeNode(width); canvas.setAttributeNode(height); ctx.drawImage(that, 0, 0, w, h); var base64 = canvas.toDataURL('image/jpeg', scale); //压缩比例 canvas = null; if (type == 'base64') { let data = { size: getBase64Size(base64), type: type, source: base64 } callback(base64); } else { let blob = base64ToBlob(base64); console.log('压缩后的大小', blob.size); const blobUrl = window.URL.createObjectURL(blob); //blob地址 blob.source = blobUrl callback(blob); } } }; /**base转Blob */ const base64ToBlob = (base64) => { var arr = base64.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while (n--) { u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], { type: mime }); }; /**获取base64的文件大小 */ const getBase64Size = () => { let size = 0; if (base64Str) { // 获取base64图片byte大小 const equalIndex = base64Str.indexOf('='); // 获取=号下标 if (equalIndex > 0) { const str = base64Str.substring(0, equalIndex); // 去除=号 const strLength = str.length; const fileLength = strLength - (strLength / 8) * 2; // 真实的图片byte大小 size = Math.floor(fileLength); // 向下取整 } else { const strLength = base64Str.length; const fileLength = strLength - (strLength / 8) * 2; size = Math.floor(fileLength); // 向下取整 } } else { size = null; } return size };

在upload-image.vue页面调用

/** 压缩图片*/ compressImg(source, compressionRatio) { let that = this; return new Promise((resolve, reject) => { that.$.compressImg(source.url, compressionRatio, source.type, compressRes => { resolve(compressRes); }) }).then((res) => { source.size = res.size // window.URL.revokeObjectURL(source.url) // 删除被压缩的缓存文件,这里注意,如果是相册选择上传,可能会删除相册的图片 source.url = res.source source.thumb = res.source return source }).catch(err => { console.log('图片压缩失败', err) }) },

完整的upload-image.vue组件代码:

import { localUrl, localResourseUrl } from '@/environments/environments.js'; import { forEach, indexOf, result } from 'lodash'; export default { name: "upload-image", props: { /** 图片默认列表*/ files: { type: Array }, /** 是否禁用*/ isdisabled: { type: Boolean, default: false }, /**是否显示删除图片的按钮 */ deletable: { type: Boolean, default: true } }, data() { return { fileList1: [], //图片列表 sizeType: ['compressed'], limitType: ['png', 'jpg', 'jpeg'], //允许的图片后缀 fileMaxSize: 1 * 1024 * 1024, // 超出1M开启压缩 maxSize:20 * 1024 * 1024, //图片最大不能超过20M fileMinSize: 5 * 1024 // 最小为5KB }; }, methods: { //文件大小超出限制 oversize() { uni.showToast({ title: "图片最大不能超过20M", icon: 'none' }) }, // 删除图片 deletePic(event) { if (this.fileList1.length === 0) { this.files.splice(event.index, 1) } else { this[`fileList${event.name}`].splice(event.index, 1) } this.imgList(this.fileList1) }, //点击图片触发 clickPreview(url, lists, name) { console.log('点击预览:', url, lists, name); }, /**获取文件大小倍数,生成质量比*/ getCompressionRatio(fileSize) { const multiple = (fileSize / this.fileMaxSize).toFixed(2); let compressionRatio = 1; if (multiple > 5) { compressionRatio = 0.5 } else if (multiple > 4) { compressionRatio = 0.6 } else if (multiple > 3) { compressionRatio = 0.7 } else if (multiple > 2) { compressionRatio = 0.8 } else if (multiple > 1) { compressionRatio = 0.9 } else { compressionRatio = 2 } return compressionRatio; }, // 读取图片 async afterRead(event) { // 当设置 multiple 为 true 时, file 为数组格式,否则为对象格式 let lists = [].concat(event.file); let fileListLen = this[`fileList${event.name}`].length; for (let index in lists) { const item = lists[index]; const fileSize = item.size; const fileName = item.name ?? ''; if(!this.isAssetTypeAnImage(item.name)) { this.$.msg('不允许该文件类型上传'); return false } console.log('文件大小',fileSize); if (fileSize > this.fileMaxSize) { const compressionRatio = this.getCompressionRatio(fileSize); if (compressionRatio > 1) { this.$.msg('文件' + fileName + '大于10M'); return false } // 超出1M自动压缩图片 await this.compressImg(item, compressionRatio) if (item.size > this.maxSize) { this.$.msg('文件' + fileName + '压缩后超出20M') return false } } if (item.size < this.fileMinSize) { this.$.msg('文件' + fileName + '不能小于5KB'); return false } this[`fileList${event.name}`].push({ ...item, status: 'uploading', message: '上传中' }) } for (let i = 0; i < lists.length; i++) { const result = await this.uploadFilePromise(lists[i].url); //调用上传图片的方法 if (!result.Success) { uni.$showMsg(result.Message); const index = this.fileList1.findIndex(event => event.name === lists[i].name) if (index !== -1) return this.fileList1.splice(index, 1); } // 垃圾回收 // window.URL.revokeObjectURL(lists[i].url); let item = this[`fileList${event.name}`][fileListLen] this[`fileList${event.name}`].splice(fileListLen, 1, Object.assign(item, { status: 'success', message: '', url: lists[i].url, res: result })) fileListLen++ } this.imgList(this.fileList1); }, /** 压缩图片*/ compressImg(source, compressionRatio) { let that = this; return new Promise((resolve, reject) => { that.$.compressImg(source.url, compressionRatio, source.type, compressRes => { resolve(compressRes); }) }).then((res) => { source.size = res.size // window.URL.revokeObjectURL(source.url) // 删除被压缩的缓存文件,这里注意,如果是相册选择上传,可能会删除相册的图片 source.url = res.source source.thumb = res.source return source }).catch(err => { console.log('图片压缩失败', err) }) }, //父组件清空图片列表 clearImgList() { this.fileList1 = [] }, //返回选择的图片列表 imgList(list) { // console.log(list); let arr = [] let newArr = [] list.map(item => { arr.push(item.res) }) arr.map(x => { newArr.push(x.Data[0]) }) this.$emit('imgList', Array.from(new Set(newArr))) }, /**判断文件类型是否正确 */ isAssetTypeAnImage(ext) { const str = ext.split('.')[1]; return this.limitType.indexOf(str.toLowerCase()) !== -1; }, /**调用上传图片的接口 */ uploadFilePromise(urls) { return new Promise((resolve, reject) => { let a = uni.uploadFile({ url: `${localUrl}system/file/Uploads`, name: 'files', filePath: urls, success: (res) => { setTimeout(() => { resolve(JSON.parse(res.data)) }, 500) }, fail:(err) => { reject(err); } }); }) }, } } image { width: 120rpx; height: 116rpx; }

注意:在图片压缩后,通过uni.uploadFile()上传的文件的FileName可能没有带后缀名,而后端大多数是根据FileName的后缀名来判断可上传的文件类型的,这时候就会出现接口对文件类型判断错误导致文件上传失败的情况。对于这个问题,我也是在网上查了很久也没有找到一个完美的解决方案。最后我换了个思路,在后端接口改为使用ContentType来校验文件类型,终于解决了这个问题!

        



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3