注意:重点关注这几个js方法:

1、递归压缩文件: doCompressImage()

2、具体的图片文件压缩方法:compressImage()

3、将Blob  转换为 base64: blobToBase64()

以下代码,可以直接拷进html文件中,在浏览器打开即可看到效果。(以下代码是h5)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>图片压缩上传</title>
    <link rel="stylesheet" href="https://www.layuicdn.com/layui-v2.5.6/css/layui.css">
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
    <script src="https://www.layuicdn.com/layui-v2.5.6/layui.js"></script>
</head>
<style>
    .info-div {
        width: 100%;display: flex;flex-direction: column;justify-content: center;align-items: center;
    }
    .title {
        width: 100%;
        font-size: 15px;
        background: linear-gradient(94deg,#69a7ea, #3c81d5 100%);
        color: #FFFFFF;
        height: 36px;
        line-height: 36px;
        font-family: PingFang SC, PingFang SC-Medium;
        margin-top: 15px;
    }
    .details_title {
        padding-left:10px
    }
  
    .btn.btn-raised.btn-inverse, .input-group-btn .btn.btn-raised.btn-inverse, .btn.btn-fab.btn-inverse, .input-group-btn .btn.btn-fab.btn-inverse, .btn-group-raised .btn.btn-inverse, .btn-group-raised .input-group-btn .btn.btn-inverse {
        background-color: #3f51b5;
        color: #ffffff;
    }
    .file-dev {
        width: 100%;
        padding-left: 15px;
    }
    .file-dev-row{
        display:flex;flex-direction: row;align-items: center;margin-top:20px;padding: 0px 20px 0px 10px
    }
  .file-dev-row-title {
        display:flex;flex-direction: row;flex: 1;align-items: center;
    }
    .uploading-catalog-btn {
        width: 54px;
        height: 25px;
        background: #009688;
        border: 1px solid #dcdfe6;
        border-radius: 3px;
        font-size: 12px;
        font-family: Microsoft YaHei;
        color: #ffffff;
        cursor: pointer;
    }
    .list-group-item {
        display: flex;
        flex-direction: row;
        justify-content: space-between;
        margin-top: 10px;
        padding-left: 15px;
        color: #5a95c1;
        padding-right: 15px;
        width: 90vw
    }
    .file-name {
        width: 100% !important;
        float: left !important;
        overflow: hidden !important;
        text-overflow: ellipsis !important;
        white-space: normal !important;
    }
</style>

<body>
    <div class="info-div">
        <div class="title">
            <p class="details_title">申请材料</p>
        </div>
        <div class="file-dev">
            <div class="file-dev-row">
                <div class="file-dev-row-title" >
                    <!-- <img src="/resource/default/static/mobile/image/icon/catalogue-icon.png" alt=""> -->
                    <p>申请人图像<span style="color:red">(必选)</span></p>
                </div>
                <button type="button" class="uploading-catalog-btn" onclick="document.getElementById('file1').click();">上传</button>
                <input type="file" style="display: none;" id="file1" class="btn btn-raised btn-inverse" name="申请人图像" onchange="changeImg(this,'file1')">
            </div>
            <ul class="list-group" id="申请人图像ul"></ul>
        </div>
    </div>
</body>
<script>


    let UploadMatList = [];//上传材料列表
    
    var imgSubmitData = {
        ApplyFileList: [],
        MatType: ""
    }
    //图片上传到服务器所需要的参数
    var imgData = {
        MATERIALNAME: "",
        PATH: "",
        EXT: ""
    }

    //选择图片事件
    function changeImg(imgObj,domeId) {
            var matTypeName = imgObj.name;
            var files = imgObj.files;
            var img = files[0];
            if (img == null) {
                return;
            }
            //取图片名字与后缀名
            var imgName = img.name;
            var index = imgName.lastIndexOf('.');
            var strtype = imgName.substr(index + 1, imgName.length - index);
            strtype = strtype.toLowerCase();
            if (!(strtype == "png" || strtype == "jpg" || strtype == "gif" || strtype == "jpeg")) {
                layui.use(['layer'], function () {
                    var layer = layui.layer
                    layer.alert('请上传gif,jpg,png,jpeg格式的图片!');
                })
                $(imgObj).val("");
            } else {
                imgName = imgName.substring(0, index);
                if (img) {
                    var reader = new FileReader();
                    reader.readAsDataURL(img);
                    reader.onload = function () {
                        var CONTENT;
                        var base64 = reader.result;
                        //图片大小 < 600kb 直接上传到服务器 如需要调整,可直接修改下面的判断
                        if(img.size <= 1024*600){
                            if (strtype == "jpg") {
                                CONTENT = base64.replace("data:image/jpeg;base64,", "");
                            } else if (strtype == "png") {
                                CONTENT = base64.replace("data:image/png;base64,", "");
                            } else if (strtype == "gif") {
                                CONTENT = base64.replace("data:image/gif;base64,", "");
                            }else if (strtype == "jpeg") {
                                CONTENT = base64.replace("data:image/jpeg;base64,", "");
                            }
                            //调用接口上传文件
                            SendRequestUploadFile(CONTENT,strtype,imgName,matTypeName,domeId);
                        }else {
                            // quality 图片质量值  wh 初始化需要缩小的宽度和高度
                            var quality = 0.8,wh = 50;
                            //多是M,只取整数部分
                            var num = parseInt(img.size/(1024*1024))
                            //quality 和 wh 重置初始值,会使下面的递归压缩次数变少,效率高一些
                            quality = 1-0.1*num
                            wh = num*wh
                            layui.use(['element', 'layer','form'], function () {
                                var layer = layui.layer;
                                var load = layer.msg("请求中...", { icon: 16,time: false, shade: 0.01});
                                try {
                                    //压缩文件
                                    doCompressImage(img,img.width,img.height,strtype,quality,wh,imgName,matTypeName,img.type,load,domeId)
                                }catch (e){
                                    if(e.message == '上传文件失败'){
                                        layer.alert("上传文件失败!");
                                    }else {
                                        layer.alert(e.message);
                                    }
                                    layer.close(load);
                                }finally {
                                    $("#"+domeId).val("")
                                }
                            })
                        }
                    };
                }
            }
    }

    //递归压缩文件
    function doCompressImage(file, maxWidth, maxHeight,fileType,quality,wh,imgName,matTypeName,type,load,domeId) {
        compressImage(file,maxWidth,maxHeight,fileType,quality,wh).then((blob)=>{
            if(blob.size > 1024*600){
                if(quality > 0.2){
                    quality = quality - 0.1
                }
                const file = new File([blob], imgName, { type: type, lastModified: Date.now() });
                doCompressImage(file,maxWidth, maxHeight,fileType,quality,wh+10,imgName,matTypeName,type,load,domeId)
            }else {
                blobToBase64(blob).then((base)=>{
                    var CONTENT;
                    if (fileType == "jpg") {
                        CONTENT = base.replace("data:image/jpeg;base64,", "");
                    } else if (fileType == "png") {
                        CONTENT = base.replace("data:image/png;base64,", "");
                    } else if (fileType == "gif") {
                        CONTENT = base.replace("data:image/gif;base64,", "");
                    }else if (fileType == "jpeg") {
                        CONTENT = base.replace("data:image/jpeg;base64,", "");
                    }
                    console.log("压缩成功!")
                    layer.close(load);
                    //上传文件
                    SendRequestUploadFile(CONTENT,fileType,imgName,matTypeName,load,domeId,domeId);
                })
            }
        })
    }

    //图片文件压缩 
    function compressImage(file, maxWidth, maxHeight,fileType,quality,wh) {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.onload = () => {
                const canvas = document.createElement('canvas');
                let width = img.width-wh;
                let height = img.height-wh;
                if (width > maxWidth) {
                    height *= maxWidth / width;
                    width = maxWidth;
                }
                if (height > maxHeight) {
                    width *= maxHeight / height;
                    height = maxHeight;
                }
                canvas.width = width;
                canvas.height = height;
                const ctx = canvas.getContext('2d');
                ctx.drawImage(img, 0, 0, width, height);
                canvas.toBlob(
                    blob => {
                        resolve(blob)
                    },
                    file.type,
                    quality // 压缩质量,可以根据需要调整
                );
            };
            img.onerror = reject;
            img.src = URL.createObjectURL(file);
        });
    }


    // 将Blob  转换为 base64
    function blobToBase64 (blob) {
        return new Promise((resolve, reject) => {
            const fileReader = new FileReader()
            fileReader.onload = (e) => {
                resolve(e.target.result)
            }
            // readAsDataURL
            fileReader.readAsDataURL(blob)
            fileReader.onerror = () => {
                reject(new Error('blobToBase64 error'))
            }
        })
    }

    //文件上传,根据自己项目中的方法来修改,这里只做参考
    function SendRequestUploadFile(base64Str,ext,imgName,matTypeName,load,domeId) {
        var imgSubmitDataCopy = JSON.parse(JSON.stringify(imgSubmitData));
        var imgDataCopy = JSON.parse(JSON.stringify(imgData));
        imgSubmitDataCopy.MatType = matTypeName;
        imgDataCopy.MATERIALNAME = imgName;
        imgDataCopy.EXT = ext;
        //上传文件接口参数
        var uploadFileBody = {
            base64Str: base64Str,
            ext: ext,
        }
        //上传文件接口地址
        var sendUrl = '';
        //具体上传方法,根据自己项目来
        /**
        httpUtil.post(sendUrl,paramStr).then(res=>{
            layer.close(load);
            if(true){
                imgDataCopy.PATH = res.data
                imgSubmitDataCopy.ApplyFileList.push(imgDataCopy);
                var falg = false;
                for (let i = 0; i < UploadMatList.length; i++) {
                    if( UploadMatList[i].MatType == matTypeName){
                        UploadMatList[i].ApplyFileList.push(imgDataCopy)
                        falg = true
                    }
                }
                if(!falg){
                    UploadMatList.push(imgSubmitDataCopy)
                }
                AddMat(imgSubmitDataCopy, imgDataCopy)
            }
        })
        **/

        //以下代码仅做参考,效果展示,真是项目中,应该在文件上传成功后执行下面代码
        imgDataCopy.PATH = ""
        imgSubmitDataCopy.ApplyFileList.push(imgDataCopy);
        var falg = false;
        for (let i = 0; i < UploadMatList.length; i++) {
            if( UploadMatList[i].MatType == matTypeName){
                UploadMatList[i].ApplyFileList.push(imgDataCopy)
                falg = true
            }
        }
        if(!falg){
            UploadMatList.push(imgSubmitDataCopy)
        }
        AddMat(imgSubmitDataCopy, imgDataCopy)
        /**
        **/
           

    }




    //添加材料
    function AddMat(imgItem, imgData) {
        //如果第一次添加,则添加
        //不是第一次,则直接往相应的数据类型材料数组里面push
        for (var i = 0; i < UploadMatList.length; i++) {
            if (UploadMatList[i].MatType == imgItem.MatType) {
                //记录在数组中的索引,以便删除
                var imgArrIndex = UploadMatList[i].ApplyFileList.length - 1;
                var content = '<li  class="list-group-item" indexID="' + imgArrIndex + '">' + '<span class="file-name">'+imgData.MATERIALNAME + imgData.EXT+'</span>'+'<span style="margin-right: 15px;color: #25a251"  onclick="lookTupian(\''+imgData.PATH +'\')">查看</span> ' +'<span style="color: red" onclick="deltr(\''+imgItem.MatType+'\','+imgArrIndex+')">删除</span> '+ '</li>'
                AddMatLi(imgItem.MatType + "ul", content);
                return;
            }
        }
    }

    //上传材料的时候添加多个材料
    function AddMatLi(toObjStr, content) {
        $("#" + toObjStr).append(content);
    }
    var deltr = function(matType,index){
        if(UploadMatList.length > 0){
            for (let i = 0; i < UploadMatList.length; i++) {
                if( UploadMatList[i].MatType == matType){
                    if(UploadMatList[i].ApplyFileList.length >= index+1){
                        UploadMatList[i].ApplyFileList.splice(index,1)
                        RemoveMatLi(matType,UploadMatList[i].ApplyFileList)
                        break
                    }
                }
            }
        }
    }
    //移除文件
    function RemoveMatLi(matType,arr) {
        $("#" + matType + "ul").html("");
        for (let i = 0; i < arr.length; i++) {
            // var content = '<li  class="list-group-item" indexID="' + i + '">' + arr[i].MATERIALNAME + arr[i].EXT +'<span style="color: red" onclick="deltr(\''+matType+'\','+i+')">删除</span> '+ '</li>'
            var content = '<li  class="list-group-item" indexID="' + i + '">' + '<span class="file-name">'+arr[i].MATERIALNAME + arr[i].EXT +'</span>'+'<span style="margin-right: 15px;color: #25a251"  onclick="lookTupian(\''+arr[i].PATH +'\')">查看</span> '+'<span style="color: red" onclick="deltr(\''+matType+'\','+i+')">删除</span> '+ '</li>'
            AddMatLi(matType + "ul", content);
        }

    }
    //初始化上传文件dom
    function createUploadFileDom(fileDate) {
        if(fileDate && fileDate.length > 0){
            fileDate.forEach((item, index) => {
                if(item.ApplyFileList && item.ApplyFileList.length > 0){
                    item.ApplyFileList.forEach((itemfile, index) => {
                        AddMat(item, itemfile)
                    })
                }
            })
        }
    }
</script>


</html>