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

一、展示

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

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

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
<title></title>
<style>
div{width: 100%;}
.logo img{display:block; margin:0 auto;}
.upload{position: relative;width: 80px;height: 18px;line-height: 18px;background: #2fc7c9;text-align: center;
color: #FFF;padding: 0px 5px;-webkit-border-radius: 2px;border-radius: 2px;
margin: 0 auto;
}
.upload form{width:100%;position:absolute; left:0; top:0;opacity:0; filter:alpha(opacity=0);}
.upload form input{width: 100%;}
</style>
</head>
<body>
<div class="logo">
<img src="img/1.jpg" />
</div>
<div class="upload">
<p>上传图片</p>
<form>
<input type="file" />
</form>
</div>
</body>
</html>

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

二、JS代码

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

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

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

三、图片压缩

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

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

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

window.fileSelected = function() {
var _this = $(this);
var file = this.files[0];
var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
if(!rFilter.test(file.type)) {
alert("文件格式必须为图片");
return;
}
/*开始进行网络加载*/
_this.css("display", "none"); //目的是为了屏蔽点击事件
var reader = new FileReader() , image = new Image() ,
canvas = document.createElement("canvas") , ctx = canvas.getContext("2d");
reader.onload = function() { //文件加载完成
var url = reader.result;
image.src = url;
};
image.onload = function() { //图片加载完成
var w = image.naturalWidth , h = image.naturalHeight ,
scale = 3; //图片缩放比例,这里是把图片大小高宽均缩小3倍
canvas.width = w / scale;
canvas.height = h / scale;
ctx.drawImage(image, 0 , 0 , w , h ,
0 , 0 , canvas.width , canvas.height);
fileUpload();
};
reader.readAsDataURL(file); //用文件加载器加载文件
function fileUpload() { //文件上传方法
var quality = 0.3; //图片的质量,这里设置的是0.3
var data = canvas.toDataURL("image/jpeg", quality);//获取画布图片,并且要jpg格式
data = data.split(',')[1];
data = window.atob(data);
var ia = new Uint8Array(data.length);
for(var i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i);
}
var blob = new Blob([ia], { //以上均为二进制参数处理,从而获取一个blob对象
type: "image/jpeg"
});
var fd = new FormData(document.getElementById("uploadForm"));
fd.append("XXX" , blob , "upload.jpg"); //向form中加入图片数据,name属性是XXX,文件名是upload.jpg
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function(resUpload) {
_this.css("display", "");
//请求成功
}, false);
xhr.addEventListener('error', function(){
_this.css("display", "");
//请求失败
}, false);
xhr.addEventListener('abort', function(){
_this.css("display", "");
//上传终止
}, false);
xhr.open('POST', "http://XXXXXXXXXXXXX");//请求地址
xhr.send(fd);//发送
}
};

关键代码

reader.readAsDataURL(file);

将文件读取为DataURL

canvas.toDataURL(type, encoderOptions); 

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

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

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

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

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

(function(window,undefind){
function imgUpLoad(options){
var defaults = {
inputId : "" , //输入框ID
formId : "" , //表单ID
paramName : "" , //输入框的name
requestUrl : "" , //请求的URL
imgSizeScale : 3 , //图片缩放比例
imgQuality : 0.3 , //图片质量
sucFun : undefind , //成功的回调函数
errFun : undefind , //失败的回调函数
abortFun : undefind //上传取消的回调函数
};
var opts = $.extend(true , defaults , options || {}) ,
_this = document.getElementById(opts.inputId);
_this.addEventListener('change' , fileChange , false);
function fileChange() {
var file = _this.files[0];
var rFilter = /^(image\/bmp|image\/gif|image\/jpeg|image\/png|image\/tiff)$/i;
if(!rFilter.test(file.type)) {
alert("文件格式必须为图片");
return;
}
var reader = new FileReader() , image = new Image() ,
canvas = document.createElement("canvas") , ctx = canvas.getContext("2d");
startFileLoad(reader , image , canvas , ctx);
}
function startFileLoad(reader , image , canvas , ctx){ //文件加载
reader.onload = function() { //文件加载完成
var url = reader.result;
image.src = url;
};
image.onload = function() { //图片加载完成
var w = image.naturalWidth , h = image.naturalHeight;
canvas.width = w / opts.imgSizeScale;
canvas.height = h / opts.imgSizeScale;
ctx.drawImage(image, 0 , 0 , w , h ,
0 , 0 , canvas.width , canvas.height);
fileUpload(canvas);
};
reader.readAsDataURL(file);
}
function fileUpload(canvas){ //文件上传
var blob = getBlob(canvas);
var fd = new FormData(document.getElementById(opts.formId));
fd.append(opts.paramName , blob , "upload.jpg");
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function(resUpload) { //请求成功
_this.style.display = "";
if(opts.sucFun && typeof opts.sucFun === "function") opts.sucFun(resUpload.currentTarget.response);
}, false);
xhr.addEventListener('error', function(){ //请求失败
_this.style.display = "";
if(opts.errFun && typeof opts.errFun === "function") opts.errFun();
}, false);
xhr.addEventListener('abort', function(){ //上传终止
_this.style.display = "";
if(opts.abortFun && typeof opts.abortFun === "function") opts.abortFun();
}, false);
xhr.open('POST', opts.requestUrl);//请求地址
xhr.send(fd);//发送
}
function getBlob(canvas){ //获取blob对象
var data = canvas.toDataURL("image/jpeg", opts.imgQuality);
data = data.split(',')[1];
data = window.atob(data);
var ia = new Uint8Array(data.length);
for(var i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i);
}
return new Blob([ia], {
type: "image/jpeg"
});
}
}
window.imgUpLoad = imgUpLoad;
})(window);

html5 实现简单的上传的更多相关文章

  1. Nodejs express、html5实现拖拽上传

    一.前言 文件上传是一个比较常见的功能,传统的选择方式的上传比较麻烦,需要先点击上传按钮,然后再找到文件的路径,然后上传.给用户体验带来很大问题.html5开始支持拖拽上传的需要的api.nodejs ...

  2. 基于html5的多图片上传,预览

    基于html5的多图片上传 本文是建立在张鑫旭大神的多文图片传的基础之上. 首先先放出来大神多图片上传的博客地址:http://www.zhangxinxu.com/wordpress/2011/09 ...

  3. 导出HTML5 Canvas图片并上传服务器功能

    这篇文章主要介绍了导出HTML5 Canvas图片并上传服务器功能,文中通过实例代码给大家介绍了HTML5 Canvas转化成图片后上传服务器,代码简单易懂非常不错,具有一定的参考借鉴价值,需要的朋友 ...

  4. LocalResizeIMG前端HTML5本地压缩图片上传,兼容移动设备IOS,android

    LocalResizeIMG前端HTML5本地压缩图片上传,兼容移动设备IOS,android jincon 发表于 2015-02-26 18:31:01 发表在: php开发 localresiz ...

  5. html5 文件拖拽上传

    本文首先发表在  码蜂笔记 : http://coderbee.net/index.php/web/20130703/266 html5 文件拖拽上传是个老话题了,网上有很多例子,我一开始的代码也是网 ...

  6. 怎么样通过php使用html5实现多文件上传?(php多图上传)

    <!DOCTYPE html><html lang="zh-cn"> <head> <meta charset="utf-8&q ...

  7. 深入研究HTML5实现图片压缩上传

    上篇文章中提到移动端上传图片,我们知道现在流量还是挺贵的,手机的像素是越来越高,拍个照动不动就是好几M,伤不起.虽然客户端可以轻轻松松实现图片压缩再上传,但是我们的应用还可能在浏览器里面打开,怎么办呢 ...

  8. HTML5手机端拍照上传

    1.accept="image/*" capture="camera" 自动调用手机端拍照功能 accept="image/*" captu ...

  9. HTML5的 input:file上传类型控制(转载)

    http://www.haorooms.com/post/input_file_leixing HTML5的 input:file上传类型控制 2014年8月29日 66352次浏览 一.input: ...

随机推荐

  1. spring boot 重定向

    /** * 测试各个html文件用. * @param model * @return */ @RequestMapping("home") public String home( ...

  2. [LeetCode] 82. Remove Duplicates from Sorted List II_Medium tag: Linked List

    Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinctnumbe ...

  3. king 选 太子

    king 选 太子 时间限制:3000 ms  |  内存限制:65535 KB 难度:1   描述 啊,从前有一个国家.此国兵强马壮,但是国王却身体不好.于是就想挑一位太子出来: 但是问题来了,国王 ...

  4. mac3.0环境搭建

    export ANDROID_SDK_ROOT=/Users/sjxxpc/Documents/ADT/sdk export ANDROID_NDK_ROOT=/Users/sjxxpc/Docume ...

  5. C# 多线程编程第一步——理解多线程

    一.进程.线程及多线程的概念 什么是多线程呢?不理解. 那什么是线程呢?说到线程就不得不说说进程.我在网上搜索也搜索了一些资料,大部分所说的进程其实是很抽象的东西.通俗的来讲,进程就是一个应用程序开始 ...

  6. SAMBA服务器的安装和配置实践

    实验需求:1) 使用RPM包安装samba服务 2) 实现匿名访问,验证可以读写文件.目录 3) 实现指定用户的访问 4) 实现指定用户的访问,并为用户赋予不同的权限 启动LINUX系统,进行SAMB ...

  7. 推荐一个js脚本的字体拟合模型

    推荐一个js脚本的字体拟合模型 http://r3mi.github.io/poly2tri.js/   推荐一个js脚本的字体拟合模型 http://r3mi.github.io/poly2tri. ...

  8. Python: 使用生成器创建新的迭代模式

    使用一个生成器函数来定义一个函数模式. def frange(start, stop, increment): x = start while x < stop: yield x x += in ...

  9. springcloud9----feign-client-without-hystrix

    package com.itmuch.cloud; import org.springframework.boot.SpringApplication; import org.springframew ...

  10. HTTP从入门到入土(3)——TCP三次握手

    TCP三次握手 客户端与服务器之间互相发送HTTP请求响应之前需要先进行TCP连接,因为HTTP是一个无连接.无状态协议,不存在连接的概念,只有请求和响应的概念.而请求和响应实际上只是数据包,他们需要 ...