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 相关文章推荐
基于jQuery的让非HTML5浏览器支持placeholder属性的代码
May 24 Javascript
jquery中.add()的使用分析
Apr 26 Javascript
JQuery对表格进行操作的常用技巧总结
Apr 23 Javascript
javascript HTML5文件上传FileReader API
Mar 27 Javascript
jQuery 全选 全部选 反选 实现代码
Aug 17 Javascript
JS验证不重复验证码
Feb 10 Javascript
整理关于Bootstrap导航的慕课笔记
Mar 29 Javascript
浅谈Node.js ORM框架Sequlize之表间关系
Jul 24 Javascript
vue router 配置路由的方法
Jul 26 Javascript
Vue 页面权限控制和登陆验证功能的实例代码
Jun 20 Javascript
vue实现自定义H5视频播放器的方法步骤
Jul 01 Javascript
JavaScript前端实现压缩图片功能
Mar 06 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引用返回与取消引用的详解
2013/06/08 PHP
解析php php_openssl.dll的作用
2013/07/01 PHP
php使用百度翻译api示例分享
2014/01/31 PHP
深入讲解PHP Session及如何保持其不过期的方法
2015/08/18 PHP
php实现图片按比例截取的方法
2017/02/06 PHP
PHP 断点续传实例详解
2017/11/11 PHP
jQuery对象和DOM对象相互转化
2009/04/24 Javascript
解析Jquery取得iframe中元素的几种方法
2013/07/04 Javascript
js动态删除div元素基本思路及实现代码
2014/05/08 Javascript
JQuery控制radio选中和不选中方法总结
2015/04/15 Javascript
Javascript实现计算个人所得税
2015/05/10 Javascript
JavaScript的History API使搜索引擎抓取AJAX内容
2015/12/07 Javascript
jQuery实现指定区域外单击关闭指定层的方法【经典】
2016/06/22 Javascript
写给vue新手们的vue渲染页面教程
2017/09/01 Javascript
微信小程序支付之c#后台实现方法
2017/10/19 Javascript
bootstrap时间插件daterangepicker使用详解
2017/10/19 Javascript
利用js给datalist或select动态添加option选项的方法
2018/01/25 Javascript
Vue实现点击后文字变色切换方法
2018/02/11 Javascript
vue自定义指令用法经典实例小结
2019/03/16 Javascript
VSCode 配置uni-app的方法
2020/07/11 Javascript
用pywin32实现windows模拟鼠标及键盘动作
2014/04/22 Python
python中abs&amp;map&amp;reduce简介
2018/02/20 Python
详解python持久化文件读写
2019/04/06 Python
PyQt5 实现字体大小自适应分辨率的方法
2019/06/18 Python
基于python3抓取pinpoint应用信息入库
2020/01/08 Python
对Tensorflow中Device实例的生成和管理详解
2020/02/04 Python
Python3.7.0 Shell添加清屏快捷键的实现示例
2020/03/23 Python
Python3操作读写CSV文件使用包过程解析
2020/04/10 Python
完美解决python针对hdfs上传和下载的问题
2020/06/05 Python
css3翻牌翻数字的示例代码
2020/02/07 HTML / CSS
商务日语专业毕业生求职信
2013/10/26 职场文书
社保缴纳证明申请书
2014/11/03 职场文书
劳动仲裁调解书
2015/05/20 职场文书
创业计划书之美容店
2019/09/16 职场文书
CSS3 制作的书本翻页特效
2021/04/13 HTML / CSS
分析SQL窗口函数之取值窗口函数
2022/04/21 Oracle