├── 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 |
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 |
47 |
57 |
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 */
--------------------------------------------------------------------------------