├── CHANGELOG.md ├── LICENSE ├── README.md ├── css └── LUploader.css ├── index.html └── js ├── LUploader.js └── LUploader.min.js /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## LUploader v1.1 - 修改于2016年3月23日 2 | * 增加quality压缩比参数,使插件更灵活 3 | * 修复多选上传功能bug(感谢网友[jerry-he](https://github.com/jerry-he)提供bug) 4 | 5 | ## LUploader - 修改于2016年3月16日 6 | * LUploader体验版诞生 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 huanglei 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | LUploader v1.1移动端图片压缩上传插件 2 | ========== 3 | 纯原生js的移动端图片压缩上传插件,不依赖任何库 4 | ##用法 5 | 在html页面中引入input标签,通过自定义属性`data-LUploader`绑定点击触发的标签id,写法如下: 6 | ``` 7 | ... 8 |
9 |
10 | 11 | 12 |
13 |
14 |
15 |

单击上传

16 |
17 |
18 | ... 19 | ``` 20 | 通过将某个自定义属性如`data-form-file`赋值`basestr`来决定上传base64字符串参数名,其他自定义属性赋值来决定其他post参数键值如`data-upload-type='front'`,如此一来post参数将成为如下样子: 21 | ``` 22 | { 23 | formFile:data:image/jpeg;base64,/9j/4......, 24 | uploadType:front 25 | } 26 | ``` 27 | 28 | 将样式文件引入到页面中: 29 | ``` 30 | ... 31 | 32 | ... 33 | ``` 34 | 同时引入js文件到页面中: 35 | ``` 36 | ... 37 | 38 | ... 39 | ``` 40 | 初始化插件: 41 | ``` 42 | ... 43 | new LUploader(这里放需要绑定的input对象作为参数, { 44 | url: '',//post请求地址 45 | multiple: false,//是否一次上传多个文件 默认false 46 | maxsize: 102400,//忽略压缩操作的文件体积上限 默认100kb 47 | accept: 'image/*',//可上传的图片类型 48 | quality: 0.1,//压缩比 默认0.1 范围0.1-1.0 越小压缩率越大 49 | showsize:false//是否显示原始文件大小 默认false 50 | }); 51 | ... 52 | ``` 53 | 调用起来非常简单,代码我后续会持续优化,如果喜欢希望客官赏颗星哦。 54 | -------------------------------------------------------------------------------- /css/LUploader.css: -------------------------------------------------------------------------------- 1 | /* 2 | * LUploader图片压缩上传插件 3 | * 4 | * 作者:黄磊 5 | * 6 | * 报告漏洞,意见或建议, 请联系邮箱:xfhxbb@yeah.net 7 | * 8 | * 创建于:2016年3月16日 9 | * 10 | * Copyright 2016 11 | * 12 | * 获得使用本类库的许可, 您必须保留著作权声明信息。 13 | */ 14 | .icon-camera{background-image:url("data:image/svg+xml;charset=utf-8,");background-size:100%}.LUploader{margin:20px 15px 15px 15px;padding:5px;text-align:center;border-radius:4px;border:1px dashed #dedde2;background:#ffffff;height:100px;position:relative}.LUploader input[data-LUploader]{display:none}.LUploader .icon{font-size:20px;margin:1.5rem auto 5px auto;width:1em;height:1em;display:block}.LUploader p{padding:0 0 20px 0;font-size:13px;color:#afb1b4}.LUploader .LUploader-container{height:100%}.LUploader .LUploader-container+div{position:absolute;top:0;left:0;width:100%;height:100%}.LUploader .LUploader-list{height:100%}.LUploader .LUploader-list li{position:relative;display:inline-block;width:100%;height:100%;background:#fff no-repeat center;background-size:cover}.LUploader .LUploader-progress{position:absolute;width:100%;height:20px;line-height:20px;bottom:0;left:0;background-color:rgba(100,149,198,0.5)}.LUploader .LUploader-progress span{display:block;width:0;height:100%;background-color:#6495c6;text-align:center;color:#FFF;font-size:13px}.LUploader .LUploader-size{position:absolute;width:100%;height:15px;line-height:15px;bottom:-18px;text-align:center;font-size:13px;color:#666} 15 | /*! 最后修改于: 2016-03-16 03:24:24 */ 16 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 移动端图片压缩上传 12 | 13 | 33 | 34 | 35 | 36 |

LUploader移动端图片压缩上传

37 |
38 |
39 | 40 | 41 |
42 |
43 |
44 |

单击上传

45 |
46 |
47 |
48 |
49 | 50 | 51 |
52 |
53 |
54 |

单击上传

55 |
56 |
57 |
58 |
59 | 60 | 61 |
62 |
63 |
64 |

单击上传

65 |
66 |
67 | 68 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /js/LUploader.js: -------------------------------------------------------------------------------- 1 | /* 2 | * LUploader图片压缩上传插件 3 | * 4 | * 作者:黄磊 5 | * 6 | * 报告漏洞,意见或建议, 请联系邮箱:xfhxbb@yeah.net 7 | * 8 | * 创建于:2016年3月16日 9 | * 10 | * Copyright 2016 11 | * 12 | * 获得使用本类库的许可, 您必须保留著作权声明信息。 13 | * 14 | */ 15 | (function() { 16 | window.LUploader = function(el, params) { 17 | var _self = this; 18 | _self.trigger=el; 19 | _self.params = { 20 | accept: 'image/*', 21 | multiple: false, 22 | maxsize: 102400, 23 | imgObj: {}, 24 | showsize: false, 25 | quality:0.1, 26 | url: '' 27 | } 28 | for (var param in params) { 29 | _self.params[param] = params[param]; 30 | } 31 | _self.init(); 32 | }; 33 | LUploader.prototype.init = function() { 34 | var _self = this; 35 | _self.trigger.setAttribute('accept', _self.params.accept); 36 | _self.params.multiple && _self.trigger.setAttribute('multiple', ''); 37 | 38 | var btn = document.querySelector('#' + _self.trigger.getAttribute('data-LUploader')); 39 | btn.addEventListener('click', function() { 40 | _self.trigger.click(); 41 | }); 42 | _self.trigger.addEventListener('change', function() { 43 | if (!this.files.length) return; 44 | var files = Array.prototype.slice.call(this.files); 45 | files.forEach(function(file, i) { 46 | if (!/\/(?:jpeg|png|gif)/i.test(file.type)) return; 47 | var reader = new FileReader(); 48 | _self.params.imgObj.size = file.size / 1024 > 1024 ? (~~(10 * file.size / 1024 / 1024)) / 10 + "MB" : ~~(file.size / 1024) + "KB"; 49 | var li = document.createElement("li"); 50 | li.innerHTML = '
'; 51 | if (_self.params.showsize) { 52 | var div_size = document.createElement('div'); 53 | div_size.className = 'LUploader-size'; 54 | div_size.textContent = _self.params.imgObj.size; 55 | li.appendChild(div_size); 56 | } 57 | var LUploaderList = _self.trigger.parentElement.querySelector('.LUploader-list'); 58 | if (!_self.params.multiple) { //假如是单个上传 59 | if (_self.old_li) { 60 | LUploaderList.removeChild(_self.old_li); 61 | } else { 62 | _self.old_li = li; 63 | } 64 | } 65 | LUploaderList.appendChild(li); 66 | LUploaderList.parentElement.nextElementSibling.style['display'] = 'none'; 67 | reader.onload = function() { 68 | var params = dataSet(_self.trigger); 69 | var url = _self.params.url; 70 | var result = this.result; 71 | var img = new Image(); 72 | _self.params.imgObj.src = img.src = result; 73 | li.style['background-image'] = 'url(' + result + ')'; 74 | if (result.length <= _self.params.maxsize) { 75 | img = null; 76 | _self.upload(url, params, result, file.type, li); 77 | return; 78 | } 79 | if (img.complete) { 80 | callback(); 81 | } else { 82 | img.onload = callback; 83 | } 84 | 85 | function callback() { 86 | var data = _self.compress(img); 87 | _self.upload(url, params, data, file.type, li); 88 | img = null; 89 | } 90 | }; 91 | reader.readAsDataURL(file); 92 | }); 93 | }); 94 | }; 95 | LUploader.prototype.compress = function(img) { 96 | var canvas = document.createElement("canvas"); 97 | var ctx = canvas.getContext('2d'); 98 | var moreCanvas = document.createElement("canvas"); 99 | var morectx = moreCanvas.getContext("2d"); 100 | var maxsize = 100 * 1024; 101 | var width = img.width; 102 | var height = img.height; 103 | var ratio; 104 | if ((ratio = width * height / 4000000) > 1) { 105 | ratio = Math.sqrt(ratio); 106 | width /= ratio; 107 | height /= ratio; 108 | } else { 109 | ratio = 1; 110 | } 111 | canvas.width = width; 112 | canvas.height = height; 113 | ctx.fillStyle = "#fff"; 114 | ctx.fillRect(0, 0, canvas.width, canvas.height); 115 | var count; 116 | if ((count = width * height / 1000000) > 1) { 117 | count = ~~(Math.sqrt(count) + 1); 118 | var nw = ~~(width / count); 119 | var nh = ~~(height / count); 120 | moreCanvas.width = nw; 121 | moreCanvas.height = nh; 122 | for (var i = 0; i < count; i++) { 123 | for (var j = 0; j < count; j++) { 124 | morectx.drawImage(img, i * nw * ratio, j * nh * ratio, nw * ratio, nh * ratio, 0, 0, nw, nh); 125 | ctx.drawImage(moreCanvas, i * nw, j * nh, nw, nh); 126 | } 127 | } 128 | } else { 129 | ctx.drawImage(img, 0, 0, width, height); 130 | } 131 | var ndata = canvas.toDataURL('image/jpeg', this.params.quality); 132 | moreCanvas.width = moreCanvas.height = canvas.width = canvas.height = 0; 133 | return ndata; 134 | }; 135 | LUploader.prototype.upload = function(url, obj, basestr, type, li) { 136 | var text = window.atob(basestr.split(",")[1]); 137 | var buffer = new Uint8Array(text.length); 138 | var pecent = 0; 139 | for (var i = 0; i < text.length; i++) { 140 | buffer[i] = text.charCodeAt(i); 141 | } 142 | var span = li.querySelector('.LUploader-progress').querySelector('span'); 143 | var xhr = new XMLHttpRequest(); 144 | xhr.open('post', url); 145 | xhr.onload = function(e) { 146 | if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 0) { 147 | var data = JSON.parse(xhr.responseText); 148 | var result = data['status']; 149 | var text = result == 0 ? '上传成功' : '上传失败'; 150 | span.style['width'] = '100%'; 151 | span.innerHTML = text; 152 | } 153 | else { 154 | span.innerHTML = '上传失败'; 155 | } 156 | } 157 | xhr.upload.addEventListener('progress', function(e) { 158 | pecent = ~~(100 * e.loaded / e.total); 159 | span.style['width'] = pecent + '%'; 160 | span.innerHTML = (pecent == 100 ? 99 : pecent) + '%'; 161 | }, false); 162 | var data = {}; 163 | for (var key in obj) { 164 | if (key !== 'luploader') { 165 | if (obj[key] == 'basestr') { 166 | data[key] = basestr; 167 | } else { 168 | data[key] = obj[key]; 169 | } 170 | } 171 | }; 172 | data = serializeObject(data); 173 | xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded; charset=UTF-8'); 174 | xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 175 | xhr.send(data); 176 | } 177 | 178 | function isArray(arr) { 179 | if (Object.prototype.toString.apply(arr) === '[object Array]') return true; 180 | else return false; 181 | }; 182 | 183 | function serializeObject(obj) { 184 | if (typeof obj === 'string') return obj; 185 | var resultArray = []; 186 | var separator = '&'; 187 | for (var prop in obj) { 188 | if (obj.hasOwnProperty(prop)) { 189 | if (isArray(obj[prop])) { 190 | var toPush = []; 191 | for (var i = 0; i < obj[prop].length; i++) { 192 | toPush.push(encodeURIComponent(prop) + '=' + encodeURIComponent(obj[prop][i])); 193 | } 194 | if (toPush.length > 0) resultArray.push(toPush.join(separator)); 195 | } else { 196 | resultArray.push(encodeURIComponent(prop) + '=' + encodeURIComponent(obj[prop])); 197 | } 198 | } 199 | 200 | } 201 | return resultArray.join(separator); 202 | }; 203 | 204 | function dataSet(el) { 205 | var dataset = {}; 206 | for (var i = 0; i < el.attributes.length; i++) { 207 | var attr = el.attributes[i]; 208 | if (attr.name.indexOf('data-') >= 0) { 209 | dataset[toCamelCase(attr.name.split('data-')[1])] = attr.value; 210 | } 211 | } 212 | return dataset; 213 | } 214 | 215 | function toCamelCase(string) { 216 | return string.toLowerCase().replace(/-(.)/g, function(match, group1) { 217 | return group1.toUpperCase(); 218 | }); 219 | }; 220 | })(); 221 | -------------------------------------------------------------------------------- /js/LUploader.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * LUploader图片压缩上传插件 3 | * 4 | * 作者:黄磊 5 | * 6 | * 报告漏洞,意见或建议, 请联系邮箱:xfhxbb@yeah.net 7 | * 8 | * 创建于:2016年3月16日 9 | * 10 | * Copyright 2016 11 | * 12 | * 获得使用本类库的许可, 您必须保留著作权声明信息。 13 | */ 14 | !function(){function a(a){return"[object Array]"===Object.prototype.toString.apply(a)?!0:!1}function b(b){if("string"==typeof b)return b;var c=[],d="&";for(var e in b)if(b.hasOwnProperty(e))if(a(b[e])){for(var f=[],g=0;g0&&c.push(f.join(d))}else c.push(encodeURIComponent(e)+"="+encodeURIComponent(b[e]));return c.join(d)}function c(a){for(var b={},c=0;c=0&&(b[d(e.name.split("data-")[1])]=e.value)}return b}function d(a){return a.toLowerCase().replace(/-(.)/g,function(a,b){return b.toUpperCase()})}window.LUploader=function(a,b){var c=this;c.trigger=a,c.params={accept:"image/*",multiple:!1,maxsize:102400,imgObj:{},showsize:!1,quality:.1,url:""};for(var d in b)c.params[d]=b[d];c.init()},LUploader.prototype.init=function(){var a=this;a.trigger.setAttribute("accept",a.params.accept),a.params.multiple&&a.trigger.setAttribute("multiple","");var b=document.querySelector("#"+a.trigger.getAttribute("data-LUploader"));b.addEventListener("click",function(){a.trigger.click()}),a.trigger.addEventListener("change",function(){if(this.files.length){var b=Array.prototype.slice.call(this.files);b.forEach(function(b,d){if(/\/(?:jpeg|png|gif)/i.test(b.type)){var e=new FileReader;a.params.imgObj.size=b.size/1024>1024?~~(10*b.size/1024/1024)/10+"MB":~~(b.size/1024)+"KB";var f=document.createElement("li");if(f.innerHTML='
',a.params.showsize){var g=document.createElement("div");g.className="LUploader-size",g.textContent=a.params.imgObj.size,f.appendChild(g)}var h=a.trigger.parentElement.querySelector(".LUploader-list");a.params.multiple||(a.old_li?h.removeChild(a.old_li):a.old_li=f),h.appendChild(f),h.parentElement.nextElementSibling.style.display="none",e.onload=function(){function d(){var c=a.compress(i);a.upload(g,e,c,b.type,f),i=null}var e=c(a.trigger),g=a.params.url,h=this.result,i=new Image;return a.params.imgObj.src=i.src=h,f.style["background-image"]="url("+h+")",h.length<=a.params.maxsize?(i=null,void a.upload(g,e,h,b.type,f)):void(i.complete?d():i.onload=d)},e.readAsDataURL(b)}})}})},LUploader.prototype.compress=function(a){var b,c=document.createElement("canvas"),d=c.getContext("2d"),e=document.createElement("canvas"),f=e.getContext("2d"),g=a.width,h=a.height;(b=g*h/4e6)>1?(b=Math.sqrt(b),g/=b,h/=b):b=1,c.width=g,c.height=h,d.fillStyle="#fff",d.fillRect(0,0,c.width,c.height);var i;if((i=g*h/1e6)>1){i=~~(Math.sqrt(i)+1);var j=~~(g/i),k=~~(h/i);e.width=j,e.height=k;for(var l=0;i>l;l++)for(var m=0;i>m;m++)f.drawImage(a,l*j*b,m*k*b,j*b,k*b,0,0,j,k),d.drawImage(e,l*j,m*k,j,k)}else d.drawImage(a,0,0,g,h);var n=c.toDataURL("image/jpeg",this.params.quality);return e.width=e.height=c.width=c.height=0,n},LUploader.prototype.upload=function(a,c,d,e,f){for(var g=window.atob(d.split(",")[1]),h=new Uint8Array(g.length),i=0,j=0;j=200&&l.status<300||0===l.status){var b=JSON.parse(l.responseText),c=b.status,d=0==c?"上传成功":"上传失败";k.style.width="100%",k.innerHTML=d}else k.innerHTML="上传失败"},l.upload.addEventListener("progress",function(a){i=~~(100*a.loaded/a.total),k.style.width=i+"%",k.innerHTML=(100==i?99:i)+"%"},!1);var m={};for(var n in c)"luploader"!==n&&("basestr"==c[n]?m[n]=d:m[n]=c[n]);m=b(m),l.setRequestHeader("Content-type","application/x-www-form-urlencoded; charset=UTF-8"),l.setRequestHeader("X-Requested-With","XMLHttpRequest"),l.send(m)}}(); 15 | /*! 最后修改于: 2016-03-23 05:49:34 */ --------------------------------------------------------------------------------