利用谷歌调式工具发现,图片大小直接影响着首屏加载时间。

且考虑到后期服务端压力,图片压缩特别必要。

本文是前端利用canvas实现图片。参考文章:https://www.cnblogs.com/007sx/p/7583202.html

本文将其改为插件形式,适合单文件压缩,多文件可以采用生成多个二进制文件的方法,然后一并上传。具体后面研究。

说说原理,压缩涉及三个关键点:

1,一个图片前端可被加载,基于file:协议的路径是不能产生onload事件,所以需要借助浏览器的接口将图片转为可加载文件,一种是通过FileReader,另一种是

通过URL.createObjectURL。

2,利用canvas,获取图片的高度和宽度之后,利用drawImage输出图片,再利用canvas的toDataURL输出base64的图片。

3,将base64转为二进制文件。

案例代码:

  1 <!DOCTYPE html>
  2 <html>
  3 
  4 <head>
  5     <meta charset="UTF-8">
  6     <title>XMLHttpRequest上传文件压缩上传图片文件</title>
  7 </head>
  8 
  9 <body>
 10     <input type="file" id="file" name="myfile" accept="image/x-png, image/jpg, image/jpeg, image/gif" />
 11     <input type="button" onclick="UpladFile()" value="上传" />
 12     <script type="text/javascript">
 13     (function() {
 14         function compress(opts, fileObj) {
 15             this.defaults = {
 16                 id: "#file",
 17                 quality: 0.4,
 18                 url: "",
 19                 callback: function(bl) {
 20                     console.log(bl);
 21                 }
 22             };
 23 
 24             if (typeof opts === "object") {
 25                 this.options = Object.assign({}, this.defaults, opts)
 26             } else {
 27                 this.options = this.defaults;
 28             }
 29             fileObj = fileObj || document.querySelector(this.options.id).files[0];
 30             this.init(fileObj);
 31         }
 32         compress.prototype = {
 33             version: "1.0.1",
 34             init: function(fileObj) {
 35                 _this = this;
 36                 //promise处理异步
 37                 this.photoCompress(fileObj).then(function(res) {
 38                     return _this.canvasDataUrl.call(_this, res);
 39                 }).catch(function(err) {
 40                     console.log(err);
 41                 }).then(function(res) {
 42                     var bl = _this.convertBase64UrlToBlob(res);
 43                     _this.options.callback(bl);
 44                 }).catch(function(err) {
 45                     console.log(err);
 46                 })
 47 
 48             },
 49             photoCompress: function(file) {
 50                 var ready = new FileReader();
 51                 ready.readAsDataURL(file);
 52                 return new Promise(function(resolve, reject) {
 53                     ready.onload = function() {
 54                         var re = this.result;
 55                         resolve(re);
 56                     }
 57                     ready.onerror = function(err) {
 58                         reject(err)
 59                     }
 60                 })
 61 
 62             },
 63             canvasDataUrl: function(res) {
 64 
 65                 var img = new Image();
 66                 img.src = res;
 67                 _this = this;
 68                 return new Promise(function(resolve, reject) {
 69                     img.onload = function() {
 70                         // 默认按比例压缩
 71                         var w = this.width,
 72                             h = this.height;
 73                         //生成canvas
 74                         var canvas = document.createElement('canvas');
 75                         var ctx = canvas.getContext('2d');
 76                         // 创建属性节点
 77                         var anw = document.createAttribute("width");
 78                         anw.nodeValue = w;
 79                         var anh = document.createAttribute("height");
 80                         anh.nodeValue = h;
 81                         canvas.setAttributeNode(anw);
 82                         canvas.setAttributeNode(anh);
 83                         ctx.drawImage(this, 0, 0, w, h);
 84 
 85                         // quality值越小,所绘制出的图像越模糊
 86                         var base64 = canvas.toDataURL('image/jpeg', _this.options.quality);
 87                         // 回调函数返回base64的值
 88                         resolve(base64)
 89                     }
 90                     img.onerror = function(err) {
 91                         reject(err)
 92                     }
 93                 })
 94             },
 95 
 96             //base64转为二进制数据,后端可直接利用
 97             convertBase64UrlToBlob: function(urlData) {
 98                 var arr = urlData.split(','),
 99                     mime = arr[0].match(/:(.*?);/)[1],
100                     bstr = atob(arr[1]),
101                     n = bstr.length,
102                     u8arr = new Uint8Array(n);
103                 while (n--) {
104                     u8arr[n] = bstr.charCodeAt(n);
105                 }
106                 return new Blob([u8arr], { type: mime });
107             }
108         }
109         window.compress = compress;
110 
111     })();
112 
113     //上传文件方法
114     function UpladFile() {
115 
116         var url = "./upload"; // 接收上传文件的后台地址 
117         new compress({
118             quality: 0.4,
119             url: url,
120             callback: function(bl) {
121                 var form = new FormData();
122                 form.append("file", bl, "file_" + Date.parse(new Date()) + ".jpg"); // 文件对象
123                 var xhr = new XMLHttpRequest();
124                 xhr.open("post", url, true);
125                 xhr.onreadystatechange = function(evt) {
126                     if (xhr.readyState === 4 && xhr.status === 200) {
127                          uploadComplete(evt);
128                     }
129                 }
130 
131                 xhr.send(form); //开始上传,发送form数据
132             }
133         })
134     }
135 
136     //上传成功响应
137     function uploadComplete(evt) {
138         //服务断接收完文件返回的结果
139         var data = JSON.parse(evt.target.responseText);
140         if (data.success) {
141             alert("上传成功!");
142         } else {
143             alert("上传失败!");
144         }
145 
146     }
147     </script>
148 </body>
149 
150 </html>
View Code

相关文章: