视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
js移动端图片压缩上传功能
2020-11-27 22:28:57 责编:小采
文档

移动端图片压缩上传功能如何实现?

做移动端开发的时候,form里面的file后台经常获取不到,用foemdata也拿不到

找到了一个formdata的脚本

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport">
 <title>移动端图片压缩上传demo</title>
 <style>
 *{margin: 0;padding: 0;}
 li{list-style-type: none;}
 a,input{outline: none;-webkit-tap-highlight-color:rgba(0,0,0,0);}
 #choose{display: none;}
 canvas{width: 100%;border: 1px solid #000000;}
 #upload{display: block;margin: 10px;height: 60px;text-align: center;line-height: 60px;border: 1px solid;border-radius: 5px;cursor: pointer;}
 .touch{background-color: #ddd;}
 .img-list{margin: 10px 5px;}
 .img-list li{position: relative;display: inline-block;width: 100px;height: 100px;margin: 5px 5px 20px 5px;border: 1px solid rgb(100,149,198);background: #fff no-repeat center;background-size: cover;}
 .progress{position: absolute;width: 100%;height: 20px;line-height: 20px;bottom: 0;left: 0;background-color:rgba(100,149,198,.5);}
 .progress span{display: block;width: 0;height: 100%;background-color:rgb(100,149,198);text-align: center;color: #FFF;font-size: 13px;}
 .size{position: absolute;width: 100%;height: 15px;line-height: 15px;bottom: -18px;text-align: center;font-size: 13px;color: #666;}
 .tips{display: block;text-align:center;font-size: 13px;margin: 10px;color: #999;}
 .pic-list{margin: 10px;line-height: 18px;font-size: 13px;}
 .pic-list a{display: block;margin: 10px 0;}
 .pic-list a img{vertical-align: middle;max-width: 30px;max-height: 30px;margin: -4px 0 0 10px;}
 </style>
</head>
<body>
<input type="file" id="choose" accept="image/*" multiple>
<ul class="img-list"></ul>
<a id="upload">上传图片</a>
<span class="tips">只允许上传jpg、png及gif</span>
<div class="pic-list">
 你上传的图片(图片有效期为1分钟):
</div>
 
<script src="https://www.gxlcms.com/public/jquery-2.1.1.min.js"></script>
<script>
 var filechooser = document.getElementById("choose");
 // 用于压缩图片的canvas
 var canvas = document.createElement("canvas");
 var ctx = canvas.getContext('2d');
 // 瓦片canvas
 var tCanvas = document.createElement("canvas");
 var tctx = tCanvas.getContext("2d");
 var maxsize = 100 * 1024;
 $("#upload").on("click", function() {
 filechooser.click();
 })
 .on("touchstart", function() {
 $(this).addClass("touch")
 })
 .on("touchend", function() {
 $(this).removeClass("touch")
 });
 filechooser.onchange = function() {
 if (!this.files.length) return;
 var files = Array.prototype.slice.call(this.files);
 if (files.length > 9) {
 alert("最多同时只可上传9张图片");
 return;
 }
 files.forEach(function(file, i) {
 if (!/\/(?:jpeg|png|gif)/i.test(file.type)) return;
 var reader = new FileReader();
 var li = document.createElement("li");
// 获取图片大小
 var size = file.size / 1024 > 1024 ? (~~(10 * file.size / 1024 / 1024)) / 10 + "MB" : ~~(file.size / 1024) + "KB";
 li.innerHTML = '<div class="progress"><span></span></div><div class="size">' + size + '</div>';
 $(".img-list").append($(li));
 reader.onload = function() {
 var result = this.result;
 var img = new Image();
 img.src = result;
 $(li).css("background-image", "url(" + result + ")");
 //如果图片大小小于100kb,则直接上传
 if (result.length <= maxsize) {
 img = null;
 upload(result, file.type, $(li));
 return;
 }
// 图片加载完毕之后进行压缩,然后上传
 if (img.complete) {
 callback();
 } else {
 img.onload = callback;
 }
 function callback() {
 var data = compress(img);
 upload(data, file.type, $(li));
 img = null;
 }
 };
 reader.readAsDataURL(file);
 })
 };
 // 使用canvas对大图片进行压缩
 function compress(img) {
 var initSize = img.src.length;
 var width = img.width;
 var height = img.height;
 //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
 var ratio;
 if ((ratio = width * height / 4000000) > 1) {
 ratio = Math.sqrt(ratio);
 width /= ratio;
 height /= ratio;
 } else {
 ratio = 1;
 }
 canvas.width = width;
 canvas.height = height;
// 铺底色
 ctx.fillStyle = "#fff";
 ctx.fillRect(0, 0, canvas.width, canvas.height);
 //如果图片像素大于100万则使用瓦片绘制
 var count;
 if ((count = width * height / 1000000) > 1) {
 count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片
// 计算每块瓦片的宽和高
 var nw = ~~(width / count);
 var nh = ~~(height / count);
 tCanvas.width = nw;
 tCanvas.height = nh;
 for (var i = 0; i < count; i++) {
 for (var j = 0; j < count; j++) {
 tctx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh);
 ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
 }
 }
 } else {
 ctx.drawImage(img, 0, 0, width, height);
 }
 //进行最小压缩
 var ndata = canvas.toDataURL('image/jpeg', 0.1);
 console.log('压缩前:' + initSize);
 console.log('压缩后:' + ndata.length);
 console.log('压缩率:' + ~~(100 * (initSize - ndata.length) / initSize) + "%");
 tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;
 return ndata;
 }
 // 图片上传,将base的图片转成二进制对象,塞进formdata上传
 function upload(basestr, type, $li) {
 var text = window.atob(basestr.split(",")[1]);
 var buffer = new Uint8Array(text.length);
 var pecent = 0, loop = null;
 for (var i = 0; i < text.length; i++) {
 buffer[i] = text.charCodeAt(i);
 }
 var blob = getBlob([buffer], type);
 var xhr = new XMLHttpRequest();
 var formdata = getFormData();
 formdata.append('imagefile', blob);
 xhr.open('post', '/cupload');
 xhr.onreadystatechange = function() {
 if (xhr.readyState == 4 && xhr.status == 200) {
 var jsonData = JSON.parse(xhr.responseText);
 var imagedata = jsonData[0] || {};
 var text = imagedata.path ? '上传成功' : '上传失败';
 console.log(text + ':' + imagedata.path);
 clearInterval(loop);
 //当收到该消息时上传完毕
 $li.find(".progress span").animate({'width': "100%"}, pecent < 95 ? 200 : 0, function() {
 $(this).html(text);
 });
 if (!imagedata.path) return;
 $(".pic-list").append('<a href="' + imagedata.path + '" rel="external nofollow" >' + imagedata.name + '(' + imagedata.size + ')<img src="' + imagedata.path + '" /></a>');
 }
 };
 //数据发送进度,前50%展示该进度
 xhr.upload.addEventListener('progress', function(e) {
 if (loop) return;
 pecent = ~~(100 * e.loaded / e.total) / 2;
 $li.find(".progress span").css('width', pecent + "%");
 if (pecent == 50) {
 mockProgress();
 }
 }, false);
 //数据后50%用模拟进度
 function mockProgress() {
 if (loop) return;
 loop = setInterval(function() {
 pecent++;
 $li.find(".progress span").css('width', pecent + "%");
 if (pecent == 99) {
 clearInterval(loop);
 }
 }, 100)
 }
 xhr.send(formdata);
 }
 /**
 * 获取blob对象的兼容性写法
 * @param buffer
 * @param format
 * @returns {*}
 */
 function getBlob(buffer, format) {
 try {
 return new Blob(buffer, {type: format});
 } catch (e) {
 var bb = new (window.BlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder);
 buffer.forEach(function(buf) {
 bb.append(buf);
 });
 return bb.getBlob(format);
 }
 }
 /**
 * 获取formdata
 */
 function getFormData() {
 var isNeedShim = ~navigator.userAgent.indexOf('Android')
 && ~navigator.vendor.indexOf('Google')
 && !~navigator.userAgent.indexOf('Chrome')
 && navigator.userAgent.match(/AppleWebKit\/(\d+)/).pop() <= 534;
 return isNeedShim ? new FormDataShim() : new FormData()
 }
 /**
 * formdata 补丁, 给不支持formdata上传blob的android机打补丁
 * @constructor
 */
 function FormDataShim() {
 console.warn('using formdata shim');
 var o = this,
 parts = [],
 boundary = Array(21).join('-') + (+new Date() * (1e16 * Math.random())).toString(36),
 oldSend = XMLHttpRequest.prototype.send;
 this.append = function(name, value, filename) {
 parts.push('--' + boundary + '\r\nContent-Disposition: form-data; name="' + name + '"');
 if (value instanceof Blob) {
 parts.push('; filename="' + (filename || 'blob') + '"\r\nContent-Type: ' + value.type + '\r\n\r\n');
 parts.push(value);
 }
 else {
 parts.push('\r\n\r\n' + value);
 }
 parts.push('\r\n');
 };
 // Override XHR send()
 XMLHttpRequest.prototype.send = function(val) {
 var fr,
 data,
 oXHR = this;
 if (val === o) {
 // Append the final boundary string
 parts.push('--' + boundary + '--\r\n');
 // Create the blob
 data = getBlob(parts);
 // Set up and read the blob into an array to be sent
 fr = new FileReader();
 fr.onload = function() {
 oldSend.call(oXHR, fr.result);
 };
 fr.onerror = function(err) {
 throw err;
 };
 fr.readAsArrayBuffer(data);
 // Set the multipart content type and boudary
 this.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
 XMLHttpRequest.prototype.send = oldSend;
 }
 else {
 oldSend.call(this, val);
 }
 };
 }
</script>
</body>
</html>

下载本文
显示全文
专题