H5中不止页面功能有了很强大的提升,就连交互功能也有和很大改善,FormData,ajax2对象可以让我们异步提交数据,包括文件对象。这是一个很不错的东西,免去了我们之前的iframe方式上传文件,提交表单的繁琐。这两个对象目前浏览器对一些常用的方法支持性尚可,可以在IE10+的浏览器中使用。甚至我们可以抛弃IE,Microsoft都放弃IE了,我们为什么还要揪着IE不放呢。
下面我们就介绍一下这两个对象中有用的方法,以及其使用方式:
FormData对象提供一种简单的方式创建一个包含键值对的form表单结构,我们可以用XMLHttpRequest.send()方法很方便的提交用FormData创建的form表单数据。我们可以通过new 的方式创建一个FormData对象。如下:
var fm=new FormData();
添加一条数据到FormData对象中,与FormData.set()方法的区别是,如果添加的数据key值已经存在,append方法会在key值对应的values末尾添加value值,而set方法会覆盖原来的values值。
从formData中删除一条key/value键值对。
返回一个迭代器对象iterator,可以遍历formData中的所有的键值对数据。
从formData对象中根据name返回第一条value的值。
var formData = new FormData(); formData.append('username', 'Chris'); formData.append('username', 'Bob'); formData.get('username'); // Returns "Chris"
从formData对象中根据name返回所有的value值组成的一个Array数组
var formData = new FormData(); formData.append('username', 'Chris'); formData.append('username', 'Bob'); formData.getAll('username'); // Returns ["Chris", "Bob"]
判断FormData对象中是否包含给定的name的键值。返回一个boolean值。
var formData = new FormData(); formData.has('username'); // Returns false formData.append('username', 'Chris'); formData.has('username'); // Returns true
返回FormData对象中所有的keys值的一个迭代器iterator。
var formData = new FormData(); formData.append('key1', 'value1'); formData.append('key2', 'value2'); // 遍历所有的key值。 //for of是ES6的一种新语法,跟for in的功能一样。 for (var key of formData.keys()) { console.log(key); }
设置formdata对象中key/value键值对,如果key已经存在,在设置value为新的value值,如果key不存在,则添加一条key/value键值对数据。
set和append方法都有第三个可选参数filename,用来添加到header中的“Content-Disposition”属性的value值发送到服务器,各个浏览器不相同。
var formData = new FormData(); formData.set('username', 'Chris'); formData.set('userpic', myFileInput.files[0], 'chris.jpg');
返回一个formData对象中所有values值的一个迭代器iterator对象,可以用来遍历所有的value值。
上述方法中提到的iterator是H5的对象迭代器对象,用来迭代遍历对象内容。
var someString = "hi"; typeof someString[Symbol.iterator]; // "function" var iterator = someString[Symbol.iterator](); iterator + ""; // "[object String Iterator]" iterator.next(); // { value: "h", done: false } iterator.next(); // { value: "i", done: false } iterator.next(); // { value: undefined, done: true }
iterator迭代其可以通过entries()方法获取。可以通过Symbol.iterator属性获取默认的迭代器,Symbol是一个常量符号对象的集合,Symbol.iterator其实就是一个常量字符串,Symbol还有一些其他的常量:比如Symbol.replace,Symbol.match等。
iterator.next()返回的done表示是否到集合的结尾,如果是true,表示已经到结尾。
Symbol,iterator的兼容性不是很好,移动端几乎不支持,电脑端目前稍微得考虑IE9+的浏览器,IE系列也全部支持,就连safari也不怎么支持。所以了解一下就性,实际项目中最好不要使用,如果非要使用,需要引入一些兼容的JS库。其实得不偿失,用我们的for循环不是美美的么,多余用迭代器何苦呢,ES添加的新功能,使得js有点失去原味的意味,不知是好是坏。新的语法太多了,这里就不展开说了,有时间单独写一篇文章介绍下。
从兼容性可以看到,对于FormData对象能放心用的方法也就append方法,其实大部分场景下,我们需要的也就只有一个append方法而已。
下面我们再来看看ajax2中的介绍:
XMLHttpRequest最开始是由微软,火狐,苹果,谷歌设计实现的,现在有了标准规范。现在XMLHttpRequest可以用来传输任何数据,不止限于XML,不止支持HTTP协议,还包括file,ftp。
var myRequest=new XMLHttpRequest();
当readState属性改变时调用的回调函数。
返回一个无符号整型数据,表示request的状态。
readyState的状态值如下:
0:UNSENT-open()方法还没有调用,
1:OPENED-open()方法已经调用,
2:HEADERS_RECEIVED-send()方法已经调用,并且headers和status已经返回是有效的。
3:LOADING-正在请求中,responseText含有部分数据。
4:DONE-请求已经完成。
这里提一句,web版聊天功能,dwr等的长连接实现就是基于readyState的状态值,服务以一直返回3值,这时候responseText有数据可以处理,就能保证client和servers保持连接,及时收到另一端client发送的信息,但是这种方式需要服务器的连接数足够才可。另一种方式是使用setTimeout或者setInterval不停的请求后台来实现此类功能。
返回的数据实体,根据XMLHttpRequest.responseType的设置,可以是ArrayBuffer,Blob,Document,JS对象,DOMString。
返回一个DOMString字符串,表示请求返回的结果中的内容文本格式,如果请求没有成功或者还没有请求则为null。
获取或设置ajax2返回数据格式的类型,可选值为:
“”(默认DOMString文本格式),
“arraybuffer”,
“blob”,
“document”,
“json”,
“text”(跟默认值相同),
返回请求的路径URL地址。
var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://example.com/test', true); xhr.onload = function () { console.log(xhr.responseURL); // http://example.com/test }; xhr.send(null);
返回一个document(xml)格式的数据,如果请求没有成功或者还没有发出请求,或者反回的数据不能转化成xml或者html,则返回null。
返回请求状态的无符号整型标志。请求返回之前状态是0,返回后状态是200.
一个无符号整型,用来设置请求的超时时间,单位是毫秒。
请求超时时的回调事件。
var xhr = new XMLHttpRequest(); xhr.open('GET', '/server', true); xhr.timeout = 2000; xhr.onload = function () { ..... }; xhr.ontimeout = function (e) { .... }; xhr.send(null);
上传进度对象。用来获取上传文件的进度。
返回一个XMLHttpRequestUpload对象,代表上传的进度,此对象可以添加以下事件监听:
onloadstart:请求开始事件回调
onprogress:数据正在传输时的回调
onbort:传输中断的回调。
onerror:传输出错时的回调。
onload:传输成功时的回调。
ontimeout:传输超时时的回调。
onloadend:传输结束时的回调,无论成功与否。
上面这些事件不止upload对象有,xhr对象也有这些事件可以调用,upload表示上传文件进度,xhr上的事件可以表示是下载进度。
event.loaded-返回上传的完成的字节数。
event.total-返回上传的总字节数
event.lengthComputable-返回boolean值,为真表示event.total不为0.
常做以下用法:
var xhr=new XMLHttpRequest(); xhr.open("post","mooshine/upload",true); var fm=new FormData(); //从input file中获取的文件files对象, //或者用过FileReader()从drop中的dataTransfer.files获取files对象。 fm.append("upfile",files[0]); xhr.upload.onprogress=function(evt){ if(evt.lengthComputable){ var percent=evt.loaded/evt.total; .... } }; xhr.send(fm);
event.loaded-已经上传的数据大小。
event.size-上传文件的总大小。
设置是否允许跨域,默认是false,如果是CORS跨域的话,需要在发送请求前设置该属性为true。
var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://example.com/', true); xhr.withCredentials = true; xhr.send(null);
如果请求已经发出,则中断请求。
获取所有的返回结果头信息,通过换行分割,是字符串形式的。如果服务器还没有返回,为null,如果网络发生错误,是空字符串。
返回特定名称name的header信息的值,如果服务器还没有返回,或者headers中不包含此字段,返回null
var client = new XMLHttpRequest(); client.open("GET", "mooshine.txt", true); client.send(); client.onreadystatechange = function() { if(this.readyState == this.HEADERS_RECEIVED) { console.log(client.getResponseHeader("Content-Type")); } }
覆盖服务器返回的MIME类型,此方法必须在send方法前调用才有作用。
初始化请求
method为请求的方法:true/false,
url为请求的路径,
async,是否是异步请求,默认为true(异步),false时为同步请求。
发送求情,如果是异步请求,请求发出就返回,如果是同步,服务器返回结果此方法才返回,会造成阻塞。
void send(); void send(null); void send(ArrayBufferViewdata); void send(Blobdata); void send(Documentdata); void send(DOMString?data); void send(FormDatadata);
send方法可以发送各种数据,并且会根据数据格式做相应的序列化处理。
设置请求的header头信息,此方法必须在open之后,send之前调用。
兼容性还算不错,抛开IE,大部分功能还是支持的。
利用ajax2和FormData的一些新特性,我们可以发送文件,还可以检测发送进度。给一段例子代码:
var xhr=new XMLHttpRequest(); xhr.open("post","upload",true); var fm=new FormData(); fm.append("upfile",files[i]); xhr.onreadystatechange=function(){ if(xhr.readyState==4&&xhr.status==200){ alert("上传功能"); } }; //上传进度 xhr.upload.onprogress=fucntion(evt){ if(evt.lengthComputable){ var percent=evt.loaded/evt.total; //更新DOM进度条的状态 .... } }; xhr.send(fm);
对照ajax2上传文件代码还ajax2的api已经formData的api,上传文件的代码还是十分简单的。最起码比不了解ajax2之前要简单的多,那种神秘感也消失了。
天不早了,睡觉了。