h5页面使用js实现图片上传(安卓用户也可拍摄、相册二选一)

思路如下:

使用原生input标签实现图片上传时,如果你的写法是如下所示:

<input 
    type="file" 
    id="upload_file" 
    @change="fileChange($event)" 
    style="display: none" 
    data-type="front"
>
fileChange(el) {
    if (!el.target.files[0].size) return;
    let currentType = el.target.dataset.type
    this.fileList(el.target.files,currentType);
    el.target.value = ''
},
// 格式限制
fileList(files,currentType) {
     for (let i = 0; i < files.length; i++) {
if(files[i].type=='image/jpeg'||files[i].type=='image/jpg'||files[i].type=='image/png'||files[i].type=='image/webp'){
          this.fileAdd(files[i],currentType);
     } else {
          return
     }
  }
},
// 获取选择的图片的base64地址
fileAdd(file,currentType) {
      let reader = new FileReader();
      reader.vue = this;
      reader.readAsDataURL(file);
      let _this = this;
      reader.onload = function () {
           file.src = this.result; // 图片的base64地址
      }
}

那你在手机中表现为:可能部分安卓只能从相册中选择照片,ios则可以拍摄、相册二选一。

为了在安卓手机也可以实现(拍摄、相册二选一)的需求,我们尝试给input标签增加accept="image/*"的属性,然后引出了新的问题

问题描述:发现在部分老机型(2016年买的手机)中当用户拍照后并没有触发input的change事件,网上有讨论说是input的value值没有改变,但如你所见,input标签上我们并没有绑定任何的value值。

最终,因为我们要实现的h5页面仅在微信浏览器环境使用,故我们改成在微信浏览器环境调用wx.chooseImage这个api来实现,关键代码如下所示:

fileClick(type) {
                var that=this
                if(that.supportWxApi) { // 微信环境,用微信提供的api
                    wx.chooseImage({
                        count: 1, // 最多可以选择的图片张数,默认9
                        sizeType: ['original','compressed'], // 可以指定是原图还是压缩图,默认二者都有'original', 'compressed'
                        sourceType: ['album','camera'], // 可以指定来源是相册还是相机,默认二者都有'album', 'camera'
                        success: function (res) {
                            /**
                             * 获取图片数据
                             */
                            wx.getLocalImgData({
                                localId: res.localIds[0].toString(),
                                success: function (result) {
                                    const localData = result.localData;
                                    let imageBase64 = '';
                                    if (localData.indexOf('data:image') == 0) {
                                        //苹果的直接赋值,默认生成'data:image/jpeg;base64,'的头部拼接
                                        imageBase64 = localData;
                                    } else {
                                        //此处是安卓中的坑!在拼接前需要对localData进行换行符的全局替换
                                        //此时一个正常的base64图片路径就完美生成赋值到img的src中了
                                        imageBase64 = 'data:image/jpeg;base64,' + localData.replace(/\n/g, '');
                                    }
                                    if(type=='front') {
                                        that.compressImg(imageBase64,function(base64Codes){
                                            console.log('base64Codes',base64Codes)
                                        })
                                    } else if(type=='back') {
                                        that.compressImg(imageBase64,function(base64Codes){
                                           console.log('base64Codes',base64Codes)
                                        })
                                    }
                                }
                            });
                        }
                    });
                } else { // 非微信环境,用原生的input上传图片
                    // 用click事件去触发change事件
                   document.getElementById('upload_file').click()
                }
            },

图片压缩

服务器那边对图片的大小有要求,故我们利用canvas来实现图片等比例压缩,

压缩图片的关键函数代码如下所示:

            // 图片压缩
            compressImg(path,callback) {
                var img = new Image();
                img.src = path;
                var objCompressed = {}
                var _this = this;
                img.onload = function() {
                    //默认压缩后图片规格
                    var quality = 0.7;
                    var w = this.width;
                    var h = this.height;
                    //实际要求
                    if (w > h) {
                        let scale = h/w
                        h = 1300;
                        w = h/scale;
                    } else {
                        let scale = w/h
                        w = 1300;
                        h = w/scale;
                    }
                    // w = objCompressed.width || w;
                    // h = objCompressed.height || (w / scale);
                    //生成canvas
                    var canvas = document.createElement('canvas');
                    var ctx = canvas.getContext('2d');
                    // 创建属性节点
                    var anw = document.createAttribute("width");
                    anw.nodeValue = w;
                    var anh = document.createAttribute("height");
                    anh.nodeValue = h;
                    canvas.setAttributeNode(anw);
                    canvas.setAttributeNode(anh);
                    ctx.drawImage(this, 0, 0, w, h);
                    var base64 = canvas.toDataURL('image/jpeg', quality);
                    callback(base64);//回调函数返回base64的值
                }
            },

图片压缩函数的使用方式如下:

that.compressImg(imageBase64,function(base64Codes){
    // imageBase64是压缩前的图片
     console.log('压缩后的大小:',that.showSize(base64Codes))                                      
})

获取base64图片的大小,返回kb数字

showSize(base64url) {
				//把头部去掉
				let str = base64url.replace('data:image/jpeg;base64,', '');
				// 找到等号,把等号也去掉
				let equalIndex = str.indexOf('=');
				if (str.indexOf('=') > 0) {
					str = str.substring(0, equalIndex);
				}
				// 原来的字符流大小,单位为字节
				let strLength = str.length;
				// 计算后得到的文件流大小,单位为字节
				let fileLength = parseInt(strLength - (strLength / 8) * 2);
				// 由字节转换为kb
				let size = "";
				size = (fileLength / 1024).toFixed(2);
				let sizeStr = size + "";
				let index = sizeStr.indexOf(".");
				let dou = sizeStr.substr(index + 1, 2);
				if (dou == "00") {
					return sizeStr.substring(0, index) + sizeStr.substr(index + 3, 2)
				}
				return size;
			},

版权声明:本文为tt18473481961原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。