Html5 ajax上传多个图片 +压缩 + nodjs保存
博客专区 > snecker 的博客 > 博客详情
Html5 ajax上传多个图片 +压缩 + nodjs保存
snecker 发表于3年前
Html5 ajax上传多个图片 +压缩 + nodjs保存
  • 发表于 3年前
  • 阅读 385
  • 收藏 15
  • 点赞 0
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

nodejs端

可以安装multer插件,npm install multer

var express = require("express");
var multer = require('multer');
var _ = require('underscore')
var app = express();
var done = false;

/*配置允许ajax跨域*/
app.use(function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
    next();
});

app.use(multer({
    dest: '../public/images/uploads/',
    rename: function (fieldname, filename) {
        return filename + Date.now();
    },
    onFileUploadStart: function (file) {
        console.log(file.originalname + ' is starting ...')
    },
    onFileUploadComplete: function (file) {
        console.log(file.fieldname + ' uploaded to  ' + file.path)
        done = true;
    }
}));

/*Handling routes.*/

app.get('/', function (req, res) {
    //输出上传页面
    res.sendfile("upload.html");
});

app.post('/api/upload', function (req, res) {
    if (done == true) {
        console.log(req.files);
        res.end(_.size(req.files)+" File uploaded.");
    }
});

/*Run the server.*/
app.listen(3000, function () {
    console.log("Working on port 3000");
});

前端

upload.html

<input id='upload' name="pic1" type="file" onchange="change(this)" multiple/>
<button id='add'>add</button>
<button id='submit' onclick="sub()">提交啊</button>

ajax

利用xhr.send(FormData)来实现


    var send2 = function(url, files) {
    		var xhr = new XMLHttpRequest;
    		xhr.open("POST", url, true);
    
    		xhr.onreadystatechange = function() {
    			if (xhr.readyState === 4) {
    				console.log('formdata', xhr.responseText);
    			}
    		};
    		var fd = new FormData;
    
    		for (var i = 0; i < files.length; i++) {
                        //如果多张图片文件名一样,需要设置不同name
                        var name = files[i].name + i;
    			fd.append(name , files[i])
    		}
    		xhr.send(fd);
    	};

利用拼接原始包的方式实现


		def('upload', function () {

	    'use strict';

	    var exports = {};

	    var prefix = '------';

	    var _boundary = "WebKitFormBoundaryLfG8DWAstG9WjKAt";//默认boundary

	    var boundaryWithPrefix = prefix + _boundary;   		

		exports.genBinString = function (data, files) {
        var CRLF = '\r\n';

        var genData = function (name, value) {
            value = value || '';
            return boundaryWithPrefix + CRLF +
                "Content-Disposition: form-data; name=\"" + name + "\"" + CRLF + CRLF                + value;
        }
        var genFile = function (name, fileName, type, bin) {
            return boundaryWithPrefix + CRLF                + 'Content-Disposition: form-data; name="' + name +'"; filename="' + fileName + '"' + CRLF                + 'Content-Type: ' + type + CRLF             + CRLF                + bin;
        };

        var resultBin = '';
        //resultBin += CRLF;
        for (var key in data) {
            resultBin += genData(key, data[key]) + CRLF;
        }
        //file
        for (var i = 0; i < files.length; i++) {
            var file = files[i];
            var type = exports.getMimeType(file.src);
            var bin = exports.getByteString(exports.compress(file.src));
            resultBin += genFile('images', file.name, type, bin) + CRLF;
        }
		resultBin += boundaryWithPrefix + '--' + CRLF;
	
		return resultBin;
		}

    	//兼容 end
   	 	exports.send = function (option) {
        var url = option.url, data = option.data, files = option.files, srcs = option.srcs,
            sucFn = option.sucFn, failFn = option.failFn,
            uploadStart = option.uploadStart, uploadProgress = option.uploadProgress, uploadSuccess = option.uploadSuccess, uploadError = option.uploadError;

        var xhr = new XMLHttpRequest;
        var upload = xhr.upload;
        //xhr.onprogress = updateProgress;//下载进度
        //上传进度
        upload.addEventListener("loadstart", uploadStart, false);
        upload.addEventListener("progress", uploadProgress, false);
        upload.addEventListener("load", uploadSuccess, false);
        upload.addEventListener("error", uploadError, false);

        xhr.open("POST", url, true);
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status == 200) {
                sucFn(JSON.parse(xhr.responseText));
            }
        };
        xhr.onerror = failFn;
        xhr.withCredentials = true;

        var fd = new FormData;
        //data
        Object.keys(data).forEach(function (key) {
            fd.append(key, data[key])
        })
        //files
        var compressedDataURIs = [];
        //递归压缩图片
        function compressFiles(files, idx, onComplete) {
            if (!files) {
                return;
            }
            var dataUri = files[idx].src;
            if (dataUri) {
                var next = function (curCompressURI) {
                    //压缩包含base64头,去掉
                    //log('压缩后:' + curCompressURI)
                    curCompressURI = curCompressURI.split(',')[1];
                    compressedDataURIs[idx] = curCompressURI;

                    if (idx == files.length - 1) {
                        return onComplete(compressedDataURIs);
                    }
                    compressFiles(files, idx + 1, onComplete);
                }
                exports.compress(dataUri, 80, next);
            }
        }

        function uncompressFiles(files) {
            if (files && files.length) {
                files.forEach(function (file) {
                    fd.append('images', file);
                })
            }
        };
        //很多浏览器压缩没有效果,暂时去掉。
        uncompressFiles(files);
        xhr.send(fd);

        //递归方式start
	       /* if (files && files.length) {
	            compressFiles(srcs, 0, function (compressedArr) {
	                //所有图片已压缩
	                if (compressedArr.length == 0 || compressedArr.join('') == '') {
	                    uncompressFiles(files);
	                } else {
	                    fd.append('base64files', JSON.stringify(compressedArr));
	                }
	                xhr.send(fd);
	            })
	        } else {
	            xhr.send(fd);
	        }*/
        //递归方式end
        /* srcs.forEach(function (file, idx) {
         var dataUri = file.src;
         //gif图,不压缩
         var type = exports.getMimeType(dataUri);
         if (type.indexOf('gif') > -1) {
         var compressDataURI = dataUri;
         } else {
         //var compressDataURI = exports.compress(dataUri, 80);
         //已经压缩过;
         var compressDataURI = dataUri;
         }
         compressDataURI = compressDataURI.split(',')[1];
         compressedDataURIs.push(compressDataURI);
         //var imageFile = new File([imageBlob], 'images');
         });

         //压缩失败则原图上传
         if (compressedDataURIs.join('').length == 0) {
         files.forEach(function (file) {
         fd.append('images', file);
         })
         } else {
         fd.append('base64files', JSON.stringify(compressedDataURIs));
         }*/
        //xhr.send(fd);
        //xhr.send(exports.genBinString(data, files));
    	}

    	//source:dataURI or img; img url保证base64;
    	exports.compress = function (source, quality, onCompressed) {
        var sourceImg = new Image();
        sourceImg.onload = function () {
            var cvs = document.createElement('canvas')

            var w = sourceImg.naturalWidth;
            var h = sourceImg.naturalHeight;
            var ratio = Math.max(w, h) / 1024;
            ratio = Math.max(1, ratio);
            cvs.width = w / ratio;
            cvs.height = h / ratio;
            var ctx = cvs.getContext("2d").drawImage(sourceImg, 0, 0, cvs.width, cvs.height);

            var mime_type = sourceImg.src.split(',')[0].split(':')[1].split(';')[0];
            var compressedDataURI = cvs.toDataURL(mime_type, quality / 100);
            //log('压缩前:' + source.length + '压缩后:' + compressedDataURI.length);
            onCompressed && onCompressed(compressedDataURI);
        }
        sourceImg.src = source;
        //return compressedDataURI;
   		}

    	//dataURI to Blob;
    	exports.dataURItoBlob = function (dataURI) {
        var byteString = exports.getByteString(dataURI);

        // separate out the mime component
        var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
        // write the bytes of the string to a typed array
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
            ia[i] = byteString.charCodeAt(i);
        }
        var blob = null;
        try {
            blob = new Blob([ia], {type: mimeString});
        } catch (e) {
            //see http://stackoverflow.com/questions/15293694/blob-constructor-browser-compatibility
            window.BlobBuilder = window.BlobBuilder ||
            window.WebKitBlobBuilder ||
            window.MozBlobBuilder ||
            window.MSBlobBuilder;

            if (e.name == 'TypeError' && window.BlobBuilder) {
                alert('blobbuilder')
                var bb = new BlobBuilder();
                bb.append([ia.buffer]);
                blob = bb.getBlob(mimeString);
            }
            else if (e.name == "InvalidStateError") {
                // InvalidStateError (tested on FF13 WinXP)
                blob = new Blob([ia.buffer], {type: mimeString});
            }
            else {
                // We're screwed, blob constructor unsupported entirely
                alert('此浏览器暂不支持上传!')
            }
        }
        return blob;
    	};

	    //convert base64/URLEncoded data component to raw binary data held in a string
	
	    exports.getByteString = function (dataURI) {
	        var byteString = '';
	        if (dataURI.split(',')[0].indexOf('base64') >= 0)
	            byteString = atob(dataURI.split(',')[1]);
	        else
	            byteString = unescape(dataURI.split(',')[1]);
	        return byteString;
	    }
	
	    exports.getMimeType = function (dataURI) {
	        return dataURI.split(',')[0].split(':')[1].split(';')[0];
	    }
	
	    return exports;
	
		})

##注:

1.问:图片压缩在iphone和一些android手机上并没有多大效果,不知道问题在哪,pc上模拟mobile确是好的

2.问:图片上传的upload。progress事件在ios6上好像没有作用。

3 扩展:压缩时可以等比缩小图片以减少上传流量,如width或height大于1024px,则按照1024的比例缩小

共有 人打赏支持
粉丝 2
博文 38
码字总数 9666
×
snecker
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: