js移动端图片压缩上传功能


Posted in Javascript onAugust 18, 2020

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

做移动端开发的时候,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="/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;
 }
 // 图片上传,将base64的图片转成二进制对象,塞进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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
一个JavaScript函数把URL参数解析成Json对象
Sep 24 Javascript
5种处理js跨域问题方法汇总
Dec 04 Javascript
浅谈jQuery.easyui的datebox格式化时间
Jun 25 Javascript
iOS + node.js使用Socket.IO框架进行实时通信示例
Apr 14 Javascript
微信小程序中hidden不生效原因的解决办法
Apr 26 Javascript
微信小程序 http请求的session管理
Jun 07 Javascript
jquery如何实现点击空白处隐藏元素
Dec 05 jQuery
Node 升级到最新稳定版的方法分享
May 17 Javascript
JavaScript数组,JSON对象实现动态添加、修改、删除功能示例
May 26 Javascript
RequireJS用法简单示例
Aug 20 Javascript
node.js中npm包管理工具用法分析
Feb 14 Javascript
Element InputNumber 计数器的实现示例
Aug 03 Javascript
微信小程序报错:this.setData is not a function的解决办法
Sep 27 #Javascript
EasyUI Tree树组件无限循环的解决方法
Sep 27 #Javascript
详解微信小程序Page中data数据操作和函数调用
Sep 27 #Javascript
深入理解Vue生命周期、手动挂载及挂载子组件
Sep 27 #Javascript
微信小程序中button组件的边框设置的实例详解
Sep 27 #Javascript
使用javaScript实现鼠标拖拽事件
Apr 03 #Javascript
vue-cli项目中怎么使用mock数据
Sep 27 #Javascript
You might like
php $_ENV为空的原因分析
2009/06/01 PHP
PHP中使用smarty生成静态文件的例子
2014/04/24 PHP
Yii2使用小技巧之通过 Composer 添加 FontAwesome 字体资源
2014/06/22 PHP
在SAE上搭建最新wordpress的方法
2014/12/21 PHP
PHP rsa加密解密使用方法
2015/04/27 PHP
javascript 函数速查表
2010/02/07 Javascript
JavaScript验证18位身份证号码最后一位正确性的实现代码
2014/08/07 Javascript
js实现从右向左缓缓浮出网页浮动层广告的方法
2015/05/09 Javascript
轻松学习jQuery插件EasyUI EasyUI实现拖放商品放置购物车
2015/11/30 Javascript
JS获取当前脚本文件的绝对路径
2016/03/02 Javascript
原生js实现焦点轮播图效果
2017/01/12 Javascript
JavaScript基础之AJAX简单的小demo
2017/01/29 Javascript
微信小程序 自定义Toast实例代码
2017/06/12 Javascript
基于Vue 服务端Cookies删除的问题
2018/09/21 Javascript
VueJs里利用CryptoJs实现加密及解密的方法示例
2019/04/29 Javascript
使用vue自定义指令开发表单验证插件validate.js
2019/05/23 Javascript
vue中移动端调取本地的复制的文本方式
2020/07/18 Javascript
使用python实现接口的方法
2017/07/07 Python
python中virtualenvwrapper安装与使用
2018/05/20 Python
Python匿名函数及应用示例
2019/04/09 Python
Pycharm+django2.2+python3.6+MySQL实现简单的考试报名系统
2019/09/05 Python
softmax及python实现过程解析
2019/09/30 Python
python TK库简单应用(实时显示子进程输出)
2019/10/29 Python
python GUI库图形界面开发之PyQt5布局控件QGridLayout详细使用方法与实例
2020/03/06 Python
Django更新models数据库结构步骤
2020/04/01 Python
浅谈css3中calc在less编译时被计算的解决办法
2017/12/04 HTML / CSS
CSS3使用transition属性实现过渡效果
2018/04/18 HTML / CSS
法国最大电子商务平台:Cdiscount
2018/03/13 全球购物
美国隐形眼镜零售商:LensPure
2019/03/10 全球购物
Kipling意大利官网:世界著名的时尚休闲包袋品牌
2019/06/05 全球购物
法学专业自我鉴定
2014/02/05 职场文书
经典演讲稿汇总
2014/05/19 职场文书
初中英语教师个人工作总结
2015/02/09 职场文书
2016年全国助残日活动总结
2016/04/01 职场文书
Win11电源已接通但未充电怎么办?Win11电源已接通未充电的解决方法
2022/04/05 数码科技
Python实现视频自动打码的示例代码
2022/04/08 Python