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利用初始化数据装配模版的实现代码
Nov 17 Javascript
如何让div span等元素能响应键盘事件操作指南
Nov 13 Javascript
javascript实现的固定位置悬浮窗口实例
Apr 30 Javascript
简述JavaScript提交表单的方式 (Using JavaScript Submit Form)
Mar 18 Javascript
Js操作DOM元素及获取浏览器高宽的简单方法
Sep 08 Javascript
实现隔行换色效果的两种方式【实用】
Nov 27 Javascript
angularJS的radio实现单项二选一的使用方法
Feb 28 Javascript
Vue中v-for的数据分组实例
Mar 07 Javascript
vue2.0 如何在hash模式下实现微信分享
Jan 22 Javascript
解决ant Design中Select设置initialValue时的大坑
Oct 29 Javascript
解决vant-UI库修改样式无效的问题
Nov 03 Javascript
Nuxt的动态路由和参数校验操作
Nov 09 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实现批量压缩图片文件大小的脚本
2014/07/04 PHP
PHP函数rtrim()使用中的怪异现象分析
2017/02/24 PHP
Thinkphp5.0 框架视图view的比较标签用法分析
2019/10/12 PHP
JavaScript Date对象 日期获取函数
2010/12/19 Javascript
jquery下为Event handler传递动态参数的代码
2011/01/06 Javascript
一个关于javascript匿名函数的问题分析
2012/03/30 Javascript
jquery用get实现ajax在ie里面刷新不进入后台解决方法
2013/08/12 Javascript
关于页面嵌入swf覆盖div层的问题的解决方法
2014/02/11 Javascript
jQuery动态添加可拖动元素完整实例(附demo源码下载)
2016/06/21 Javascript
深入浅析JavaScript函数前面的加号和叹号
2016/07/09 Javascript
jQuery实现侧浮窗与中浮窗切换效果的方法
2016/09/05 Javascript
js基础之DOM中元素对象的属性方法详解
2016/10/28 Javascript
localStorage实现便签小程序
2016/11/28 Javascript
微信小程序本地缓存数据增删改查实例详解
2017/05/24 Javascript
axios进阶实践之利用最优雅的方式写ajax请求
2017/12/20 Javascript
vue 设置proxyTable参数进行代理跨域
2018/04/09 Javascript
vue cli4下环境变量和模式示例详解
2020/04/09 Javascript
解决vue动态路由异步加载import组件,加载不到module的问题
2020/07/26 Javascript
python实现的阳历转阴历(农历)算法
2014/04/25 Python
用Python实现一个简单的能够发送带附件的邮件程序的教程
2015/04/08 Python
详解python中xlrd包的安装与处理Excel表格
2016/12/16 Python
分享Python切分字符串的一个不错方法
2018/12/14 Python
python 使用pandas计算累积求和的方法
2019/02/08 Python
Python语言进阶知识点总结
2019/05/28 Python
django的model操作汇整详解
2019/07/26 Python
Pytorch中Tensor与各种图像格式的相互转化详解
2019/12/26 Python
使用Python三角函数公式计算三角形的夹角案例
2020/04/15 Python
详解HTML5布局和HTML5标签
2020/10/26 HTML / CSS
Bogner美国官网:滑雪服中的”Dior”
2018/01/30 全球购物
Myprotein法国官网:欧洲第一运动营养品牌
2019/03/26 全球购物
白酒市场开发计划书
2014/01/09 职场文书
电影圆明园观后感
2015/06/03 职场文书
陶瓷类经典广告语集锦
2019/10/25 职场文书
python 实现定时任务的四种方式
2021/04/01 Python
python opencv通过4坐标剪裁图片
2021/06/05 Python
app场景下uniapp的扫码记录
2022/07/23 Java/Android