简单记录下今早做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. centos shell脚本编程2 if 判断 case判断 shell脚本中的循环 for while shell中的函数 break continue test 命令 第三十六节课

    centos  shell脚本编程2 if 判断  case判断   shell脚本中的循环  for   while   shell中的函数  break  continue  test 命令   ...

  2. HDU1573:X问题(解一元线性同余方程组)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1573 题目解析;HDU就是坑,就是因为n,m定义成了__int64就WAY,改成int就A了,无语. 这题 ...

  3. 1059. C语言竞赛(20)

    原题: https://www.patest.cn/contests/pat-b-practise/1059 思路: 参赛者id是数组下标, 数组值是参赛者排名位置(从1开始), 每次判断0不存在, ...

  4. ABP常见问题

    System.Data.SqlClient.SqlException (0x80131904): 'OFFSET' 附近有语法错误 解决方案:最新的ABP默认支持的是sql2012以上的版本,对于之前 ...

  5. docker——安全防护与配置

    Docker是基于Linux操作系统实现的应用虚拟化.运行在容器内的进程,跟运行在本地系统的进程本质上并无区别,配置不合适的安全策略将可能给本地系统带来安全风险,因此,Docker的安全性在生产环境中 ...

  6. uva10537 dijkstra + 逆推

    21:49:45 2015-03-09 传送 http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8& ...

  7. Java String、StringBuffer、StringBuilder有什么区别

    ① String是Java语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑.它是典型的immutable类,被声明成final class,所有属性也都是final的,由于它的不可变性,类 ...

  8. window.location.href = basePath + "paper/deleteExpertComment.action?expertId="+$(this).prev().val();

    window.location.href = basePath + "paper/deleteExpertComment.action?expertId="+$(this).pre ...

  9. 抓包工具Charles简单使用介绍

    一是拦截别人软件的发送的请求和后端接口,练习开发. 二是自己后端返回的response拦截修改后再接收以达到测试临界数据的作用. 三写脚本重复拦截抓取别人的数据. 四支持流量控制,可以模拟慢速网络以及 ...

  10. PHP设计模式_适配器模式

    将各种截然不同的函数接口封装成统一的API. PHP中的数据库操作有MySQL,MySQLi,PDO三种,可以用适配器模式统一成一致,使不同的数据库操作,统一成一样的API.类似的场景还有cache适 ...