简单记录下今早做H5上传中一些代码还有坑

一、展示

因为前端上传文件是必须通过form表单的,不能使用ajax,这样的话一个移动页面放入一个type为file的input真心不怎么好看,如下图,很挫有没有

解决办法找了下,PC上有些是把这个input换成flash,采用jquery的工具库比如uploadify来做,但是移动端大部分浏览器是不支持flash的。所以最后采用的办法还是用form表单的形式,只是把这个form和input的透明度设置为0,让它们和准备显示的内容同时在一个div中,显示的内容可以做成自己想要的样子。代码如下:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
  6. <title></title>
  7. <style>
  8. div{width: 100%;}
  9. .logo img{display:block; margin:0 auto;}
  10. .upload{position: relative;width: 80px;height: 18px;line-height: 18px;background: #2fc7c9;text-align: center;
  11. color: #FFF;padding: 0px 5px;-webkit-border-radius: 2px;border-radius: 2px;
  12. margin: 0 auto;
  13. }
  14. .upload form{width:100%;position:absolute; left:0; top:0;opacity:0; filter:alpha(opacity=0);}
  15. .upload form input{width: 100%;}
  16. </style>
  17. </head>
  18. <body>
  19. <div class="logo">
  20. <img src="img/1.jpg" />
  21. </div>
  22. <div class="upload">
  23. <p>上传图片</p>
  24. <form>
  25. <input type="file" />
  26. </form>
  27. </div>
  28. </body>
  29. </html>

样子如左图,这样展现就在“上传图片”这个p标签中,点击它就有选择file的效果

 

二、JS代码

我这边写的蛮简单的,只是用了下h5上传的的基本功能

html代码如下,action为要请求的路径,我这边做的是当文件发生改变时就上传修改头像,input标签的name属性不能省去,具体跟后端接口有关

  1. <form id="uploadForm" enctype="multipart/form-data" method="post" action="XXXXXX">
  2. <input type="file" name="imageFile" id="imageFile" onchange="fileSelected()" />
  3. </form>
  1. var iMaxFilesize = 2097152; //2M
  2. window.fileSelected = function() {
  3. var oFile = document.getElementById(\'imageFile\').files[0]; //读取文件
  4. var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
  5. if (!rFilter.test(oFile.type)) {
  6. alert("文件格式必须为图片");
  7. return;
  8. }
  9. if (oFile.size > iMaxFilesize) {
  10. alert("图片大小不能超过2M");
  11. return;
  12. }
  13. var vFD = new FormData(document.getElementById(\'uploadForm\')), //建立请求和数据
  14. oXHR = new XMLHttpRequest();
  15. oXHR.addEventListener(\'load\', function(resUpload) {
  16. //成功
  17. }, false);
  18. oXHR.addEventListener(\'error\', function() {
  19. //失败
  20. }, false);
  21. oXHR.addEventListener(\'abort\', function() {
  22. //上传中断
  23. }, false);
  24. oXHR.open(\'POST\', actionUrl);
  25. oXHR.send(vFD);
  26. };

 

三、图片压缩

在开发中,特别是在移动端往往一张图片大小在3,4M左右,这样的图片上传会给服务器带来不少压力,同时也有不少接口对img的大小有所要求,比如不能超过200K,那手机相册的照片大多是见了鬼的,都上传不了。在html5的功能中,可以将图片压缩大小(尺寸)放到canvas画布上,然后截取canvas画布上的图片,转变为二进制的数据,通过blob进行再次压缩生成图片文件,这样手机上4M左右图片传到服务器上也就100K左右了。

  1. <input type="file" name="imageFile" id="imageFile" onchange="fileSelected()" />
  2. <form id="uploadForm" enctype="multipart/form-data" method="post" action="XXXXXX">
  3. <input hidden="hidden" name="param" value="test" />
  4. </form>

当文件改变时,对图片进行压缩上传

  1. window.fileSelected = function() {
  2. var _this = $(this);
  3. var file = this.files[0];
  4. var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
  5. if(!rFilter.test(file.type)) {
  6. alert("文件格式必须为图片");
  7. return;
  8. }
  9. /*开始进行网络加载*/
  10. _this.css("display", "none"); //目的是为了屏蔽点击事件
  11. var reader = new FileReader() , image = new Image() ,
  12. canvas = document.createElement("canvas") , ctx = canvas.getContext("2d");
  13. reader.onload = function() { //文件加载完成
  14. var url = reader.result;
  15. image.src = url;
  16. };
  17. image.onload = function() { //图片加载完成
  18. var w = image.naturalWidth , h = image.naturalHeight ,
  19. scale = 3; //图片缩放比例,这里是把图片大小高宽均缩小3倍
  20. canvas.width = w / scale;
  21. canvas.height = h / scale;
  22. ctx.drawImage(image, 0 , 0 , w , h ,
  23. 0 , 0 , canvas.width , canvas.height);
  24. fileUpload();
  25. };
  26. reader.readAsDataURL(file); //用文件加载器加载文件
  27. function fileUpload() { //文件上传方法
  28. var quality = 0.3; //图片的质量,这里设置的是0.3
  29. var data = canvas.toDataURL("image/jpeg", quality);//获取画布图片,并且要jpg格式
  30. data = data.split(\',\')[1];
  31. data = window.atob(data);
  32. var ia = new Uint8Array(data.length);
  33. for(var i = 0; i < data.length; i++) {
  34. ia[i] = data.charCodeAt(i);
  35. }
  36. var blob = new Blob([ia], { //以上均为二进制参数处理,从而获取一个blob对象
  37. type: "image/jpeg"
  38. });
  39. var fd = new FormData(document.getElementById("uploadForm"));
  40. fd.append("XXX" , blob , "upload.jpg"); //向form中加入图片数据,name属性是XXX,文件名是upload.jpg
  41. var xhr = new XMLHttpRequest();
  42. xhr.addEventListener(\'load\', function(resUpload) {
  43. _this.css("display", "");
  44. //请求成功
  45. }, false);
  46. xhr.addEventListener(\'error\', function(){
  47. _this.css("display", "");
  48. //请求失败
  49. }, false);
  50. xhr.addEventListener(\'abort\', function(){
  51. _this.css("display", "");
  52. //上传终止
  53. }, false);
  54. xhr.open(\'POST\', "http://XXXXXXXXXXXXX");//请求地址
  55. xhr.send(fd);//发送
  56. }
  57. };

关键代码

  1. reader.readAsDataURL(file);

将文件读取为DataURL

  1. canvas.toDataURL(type, encoderOptions);

实际上就是读取canvas画布上图片的数据。其默认是png格式,如果第一个参数type是image/jpeg的话,第二个参数encoderOptions就可以用来设置图片的压缩质量。

  1. var quality = 0.3; //图片的质量,这里设置的是0.3
  2. var data = canvas.toDataURL("image/jpeg", quality);//获取画布图片,并且要jpg格式
  3. data = data.split(\',\')[1];
  4. data = window.atob(data);
  5. var ia = new Uint8Array(data.length);
  6. for(var i = 0; i < data.length; i++) {
  7. ia[i] = data.charCodeAt(i);
  8. }
  9. var blob = new Blob([ia], { //以上均为二进制参数处理,从而获取一个blob对象
  10. type: "image/jpeg"
  11. });

这一段代码的的目的是为了解码图片数据,然后返回一个Blob对象,对象的格式是jpg。aton其作用是做解码,因为图片格式的base64,该方法解码出来可能是一堆乱码,Uint8Array返回的是8进制整型数组。

Blob是存储二进制文件的容器,典型的Blob对象是一个图片或者声音文件,其默认是PNG格式。最后的blob就可以传给服务端了。

整理成一个插件,代码如下

  1. (function(window,undefind){
  2. function imgUpLoad(options){
  3. var defaults = {
  4. inputId : "" , //输入框ID
  5. formId : "" , //表单ID
  6. paramName : "" , //输入框的name
  7. requestUrl : "" , //请求的URL
  8. imgSizeScale : 3 , //图片缩放比例
  9. imgQuality : 0.3 , //图片质量
  10. sucFun : undefind , //成功的回调函数
  11. errFun : undefind , //失败的回调函数
  12. abortFun : undefind //上传取消的回调函数
  13. };
  14. var opts = $.extend(true , defaults , options || {}) ,
  15. _this = document.getElementById(opts.inputId);
  16. _this.addEventListener(\'change\' , fileChange , false);
  17. function fileChange() {
  18. var file = _this.files[0];
  19. var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
  20. if(!rFilter.test(file.type)) {
  21. alert("文件格式必须为图片");
  22. return;
  23. }
  24. var reader = new FileReader() , image = new Image() ,
  25. canvas = document.createElement("canvas") , ctx = canvas.getContext("2d");
  26. startFileLoad(reader , image , canvas , ctx);
  27. }
  28. function startFileLoad(reader , image , canvas , ctx){ //文件加载
  29. reader.onload = function() { //文件加载完成
  30. var url = reader.result;
  31. image.src = url;
  32. };
  33. image.onload = function() { //图片加载完成
  34. var w = image.naturalWidth , h = image.naturalHeight;
  35. canvas.width = w / opts.imgSizeScale;
  36. canvas.height = h / opts.imgSizeScale;
  37. ctx.drawImage(image, 0 , 0 , w , h ,
  38. 0 , 0 , canvas.width , canvas.height);
  39. fileUpload(canvas);
  40. };
  41. reader.readAsDataURL(file);
  42. }
  43. function fileUpload(canvas){ //文件上传
  44. var blob = getBlob(canvas);
  45. var fd = new FormData(document.getElementById(opts.formId));
  46. fd.append(opts.paramName , blob , "upload.jpg");
  47. var xhr = new XMLHttpRequest();
  48. xhr.addEventListener(\'load\', function(resUpload) { //请求成功
  49. _this.style.display = "";
  50. if(opts.sucFun && typeof opts.sucFun === "function") opts.sucFun(resUpload.currentTarget.response);
  51. }, false);
  52. xhr.addEventListener(\'error\', function(){ //请求失败
  53. _this.style.display = "";
  54. if(opts.errFun && typeof opts.errFun === "function") opts.errFun();
  55. }, false);
  56. xhr.addEventListener(\'abort\', function(){ //上传终止
  57. _this.style.display = "";
  58. if(opts.abortFun && typeof opts.abortFun === "function") opts.abortFun();
  59. }, false);
  60. xhr.open(\'POST\', opts.requestUrl);//请求地址
  61. xhr.send(fd);//发送
  62. }
  63. function getBlob(canvas){ //获取blob对象
  64. var data = canvas.toDataURL("image/jpeg", opts.imgQuality);
  65. data = data.split(\',\')[1];
  66. data = window.atob(data);
  67. var ia = new Uint8Array(data.length);
  68. for(var i = 0; i < data.length; i++) {
  69. ia[i] = data.charCodeAt(i);
  70. }
  71. return new Blob([ia], {
  72. type: "image/jpeg"
  73. });
  74. }
  75. }
  76. window.imgUpLoad = imgUpLoad;
  77. })(window);

 

版权声明:本文为skyHF原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/skyHF/p/5145334.html