uniapp图片上传与压缩,兼容小程序与H5

  • 图片上传借助了Uview2.0的组件
<u-upload :fileList="imgs" :name="" @afterRead="afterRead" :deletable="true" multiple @delete="deletePic" :maxCount="4" width="112rpx" height="112rpx">
    <image src="../../../static/imgs/common/uploadImg.png" mode="widthFix" style="width: 112rpx; height: 112rpx;" :previewFullImage="true"></image>
</u-upload>
<view class="save" @click="$u.throttle(clickSave,500)">保存</view>
<helang-compress ref="helangCompress"></helang-compress> //uniapp插件市场图片压缩工具(https://ext.dcloud.net.cn/plugin?id=2316)
<script>
export default {
    data(){
        return {
                imgs: [],
            },
        }
    },
    methods:{
        // 删除图片
        deletePic(event) {
            this.imgs.splice(event.index, 1)
        },
        // 新增图片
        async afterRead(event) {
            let lists = [].concat(event.file)
            this.imgs = this.imgs.concat(lists.map(item => ({ url: item.url })));
        },
        async clickSave(){
            let updateData =  this.imgs.map(img => img.url)
            uni.showLoading({
                title: '资料上传中...',
                mask: true
            });
            for (let i = 0; i < updateData.length; i++) {
                const img = updateData[i]
                //如果当前的图片地址是以当前域名为开头的,则表示是服务器返回的图片,无需进行处理,否则则是本地图片,需要上传到服务器,在上传之前先对图片进行压缩,压缩与上传之后将本地图片替换成网络图片,这样发给后端的时候,图片地址统一为网络地址形式的图片了
                if (!img.startsWith(config.baseUrl)) {
                    const uploadedUrl = await this.imageUpload(img)
                    updateData.imgs[i] = uploadedUrl
                }
            }
            
            const params = { id: this.id, pay_img: JSON.stringify(updateData) };
            const result = await goodsLink(params);
            uni.hideLoading();
            if(result.code===1){
                this.$u.toast(result.msg, 1000);
                //上传成功的逻辑
            }else{
                this.$u.toast(result.msg)
            }
        },
        //上传图片到服务器,由于微信小程序只支持单文件上传,传多个文件需要反复调用api
        async imageUpload(filePath){
            let originSize
            let finallPath
            //判断本地文件的大小
            uni.getFileInfo({
                filePath: filePath,
                success:({size})=>{
                    originSize = size
                }
            });
            //如果图片小于1M,则不走压缩逻辑,只是转化一下图片的格式,在H5中,图片会由blob转化为文件格式(接口需求)
            if( originSize < 1024*1024){
                finallPath = await exchangeFile(filePath)
            }else{
            //图片大于1M,走压缩
                finallPath = await compressImage.call(this, filePath); // 压缩图片
            }
            const url = config.baseUrl + 'api.php/user/upload_sign_img';
            const token = uni.getStorageSync('user').token;
            //判断当前的平台
            const type = uni.getSystemInfoSync().uniPlatform
            if (type === 'web') {
            //在h5中,使用文件的方式上传
                return new Promise((resolve, reject) => { 
                    uni.uploadFile({
                        url: url,
                        file: finallPath,
                        header:{"AUTHORIZATION": token},
                        fail: err => {
                            reject(err); 
                        },
                        success: res => {
                            const data = JSON.parse(res.data);
                            if (data.data && data.data.file_urls) {
                                const imageUrl = data.data.file_urls;
                                resolve(imageUrl); 
                            } else {
                                reject(data.data); 
                            }
                        },
                    });
                })
            }else{
                return new Promise((resolve,reject)=>{
                    uni.uploadFile({
                    url: url,
                    filePath: finallPath,
                    header:{"AUTHORIZATION": token},
                    name: 'file', 
                    fail: err => {
                        this.$u.toast(err);
                    },
                    success: res => {
                        const data = JSON.parse(res.data);
                        if(data.data && data.data.file_urls){
                            // 上传成功的情况
                            const imageUrl = data.data.file_urls;
                            resolve(imageUrl)
                        }else{
                            this.$u.toast(data.data);
                        }
                    },
                });
            })}
        },
	}
}

</script>
  • 压缩代码
const type = uni.getSystemInfoSync().uniPlatform
// 把blob转为file(h5环境使用)
function dataURLtoFile(dataUrl, filename) {
    const arr = dataUrl.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    return new File([u8arr], filename, { type: mime });
}
function exchangeFile(imageUrl){
    if(type === 'web'){
        imageUrl = dataURLtoFile(imageUrl, 'filename.jpg');
    }
    return new Promise((resolve,reject)=>{
        resolve(imageUrl)
    })
}
//图片压缩处理
async function compressImage(imageUrl) {
    let compressedUrl = imageUrl;
    let count = 0; // 定义一个计数器,用于记录循环次数
    while (count < 5) { // 最多循环5次
        count++; // 对计数器加1
        await new Promise((resolve, reject) => {
            this.$refs.helangCompress.compress({
                src: compressedUrl,
                maxSize: 800,
                fileType: 'jpg',
                quality: 0.85,
                minSize: 640 
            }).then((res) => {
                uni.getFileInfo({
                    filePath: res,
                    success: ({size}) => {
                        console.log(size, '压缩后的文件大小');
                        if (size < 4096 * 1024) { // 小于 4MB,压缩成功
                            console.log('压缩成功');
                            compressedUrl = res; // 更新压缩后的图片路径
                            resolve();
                        } else { // 大于等于 4MB,继续压缩
                            compressedUrl = res; // 更新压缩后的图片路径
                            console.log('再次压缩');
                            resolve();
                        }
                    }
                })
            }).catch((err) => {
                console.log(err);
                reject(err);
            });
        });
        if (compressedUrl) break; // 如果已经成功压缩图片,则退出循环
    }

    if (!compressedUrl) {
        throw new Error('经过5次重试仍无法成功压缩图片');
    }
   
    if(type === 'web'){
        compressedUrl = dataURLtoFile(compressedUrl, 'filename.jpg');
    }
    return compressedUrl;
}
export { exchangeFile, compressImage };