在Long Long Ago,那个前端还是一个切图仔的年代,那时的页面根本没有js,前端的api非常的少,页面的所有数据都来自服务器渲染,任何的页面操作都会提交form表单请求刷新页面,直到那一天,浏览器开发者给浏览器挖通了一条可以不刷新页面就从服务器获取数据的通道,以及大量的es更新,那一天前端咸鱼翻身了,这个api叫window.XMLHttpRequest
,这个技术叫AJAX
,全称Asynchronous JavaScript And XML
(异步的 JavaScript 和 XML)
前端就是一个把数据请求到然后加工然后展示给用户看的一个工作,把数据请求到就是第一步,没有数据,前端跟一条咸鱼有什么区别
一个ajax只有发出一次请求(一份参数)获取到一次响应(一份结果)
ajax请求需要的材料是一个请求地址和请求参数
但是发起请求的数据格式有很多,这决定了后端能否拿到数据,
能决定数据格式的因素有请求方式和请求体和Content-Type请求头
把ajax比作寄快递,你就是拿着数据去一个叫net的快递公司寄快递,到了之后可以选择他们的车(请求方式)
请求方式是车,有四种车
- GET
- POST
- PUT
- DELETE
车速是一样的,但是车能装的东西有规定,而且车上的箱子也不一样
箱子有两种
- 一个是拼接在请求地址后面,叫做params
- 一个是放在一个叫请求体的地方,叫做body
GET的车上只有一个箱子,是params,其他三种车是两种箱子都有
你去寄快递,如果你选择把东西放在body箱子里寄,他会问你寄的是什么,这就是type请求头,type请求头就是告诉net公司,我寄的是什么,他会根据你寄的东西不一样,打包装,打包装是net的事,你不用管,只要如实的告诉他们无数据格式,如果你不说,他有默认的type请求头,parmas箱子不需要type请求头,因为parmas只有一个格式
Content-Type请求头有
- application/x-www-form-urlencoded(默认请求头)
- multipart/form-data
- application/json
- text/xml
上面三种因素的分类可以组合出几十种寄快递的方式
但是,会出现几种情况
- 寄了没发(格式不符合规定)
- 发了对方拿不到
- 对方拿到了,但是你寄的时候说错了格式,对方拿到的是一串乱码
下面列出所有常用的能顺利完成一次快递过程的方式,发请求的选择就是根据数据类型来选择的
如果你要发下面这种key-value的并且是基础数据类型的数据
{
name: "tom"
age: 18,
}
可以选择get,get会打包成name=tom&age=18;
也可以选择(POST | PUT | DELETE) 和 application/x-www-form-urlencoded,会被打包成跟上面一样的数据,但是是放在body的箱子里的,上面是放在params的箱子里;
还有(POST | PUT | DELETE) 和 application/json,这个特殊,往下看
选哪种要看
如果你要发文件格式
选择(POST | PUT | DELETE) 和 multipart/form-data
如果你要发复杂数据类型,比如数组和对象,普通的key-value同样适用,最常用
{
obj: { name:"tom",age:18 },
arr: [1,2,3]
}
选择(POST | PUT | DELETE) 和 application/json
但是不是像上面那么写,而是把这个数据转成json字符串格式
JSON.stringify({
obj: { name:"tom",age:18 },
arr: [1,2,3]
})
如果你要发xml类型的数据
选择(POST | PUT | DELETE) 和 text/xml
xml数据类型现在在前端很少见了,这个可以不理会的,就了解一下,xml数据类型在下一篇会说
也就是5种方式,减掉xml的不说,4种
下面用这四种搭配写四个jq.ajax
的模板供复制使用
为什么用jq的ajax,因为自己学个ajax插件是不存在的,判断太多了,今后还会接触到另外的插件,会用就行,当然,原理还是要懂的,最下面会写一个原生的ajax请求
需要先了解ajax的F12调试手段
F12的第6个选项Network就是浏览器的请求数据,net就是网络,work就是工作;
一切的请求在第2个红框的All都能看到,包括图片,css文件,js文件,doc文件等等;
点击第3个红框的xhr就可以筛选出ajax的所有请求;
第四框就是一个请求的列表;
第五个框headers请求信息的显示位置,里面包括了(general,responseHeaders,RequestHeaders,数据包装区);
第6的General查看请求地址,请求方式,请求头,请求参数,请求cookie的地方(还有响应头,响应cookie);
第7的responseHeaders查看请求头,请求cookie的地方;
第8的RequestHeaders查看响应头,响应cookie的地方;
第9的数据包装区,根据请求头不同有多种名字,截图是Parametes
第10是查看接口返回数据的地方
好了,上代码上截图
GET
$.ajax({
url:"xxxx",
type:"get",
// get没有请求头
// data只能是传key-value,value不能是数组对象等复杂数据格式
data:{
name:"pdt",
age:18
}
})
post 和 application/x-www-form-urlencoded
$.ajax({
url:"xxxx",
type:"post",
// 不用写这句话因为这是默认的
// contentType:"application/x-www-form-urlencoded",
// data只能是传key-value,value不能是数组对象等复杂数据格式
data:{
name:"pdt",
age:18
}
})
post 和 multipart/form-data
在这里要插入form表单提交文件的写法,进行对比
<form enctype="multipart/form-data" action="xxxx" method="post">
<input name="file" type="file" />
<input type="submit" value="提交" />
</form>
因为form表单提交会跳转页面,所以根本来不及截图,所以这里需要阻止跳转,阻止跳转的方式有两种,一种是iframe,一种是使用jq.from插件
iframe方式,这种方式内嵌页面,很好写不需要插件,但是在调试页面看不到请求详情
<form enctype="multipart/form-data" action="xxxx" method="post" target="iframe">
<!-- 创建一个iframe 标签,标签加上name属性,
form表单添加target属性等于iframe的name -->
<iframe id="iframe" name="iframe" style="display:none"></iframe>
<input name="file" type="file" />
<input type="submit" value="提交" />
</form>
//获取数据
var iframe= document.getElementById(iframe);
iframe.onload = function() {
var body = (iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument).document.body;
var json = (body.innerText) ? body.innerText : ( (body.textContent) ? body.textContent : null);
//json就是iframe里请求返回的数据
console.log(json);
}
jq.form方式,需要先引入插件
<form enctype="multipart/form-data" action="xxxx" method="post" id="aa">
<input name="file" type="file" onchange="changeUpload()"/>
</form>
function changeUpload(){
// res就是后台返回的值
$("#aa").ajaxSubmit(function(res) { ... });
// 返回false,阻止跳转
return false;
}
用jqform可以看到,请求体的格式很奇怪,如果我们用ajax怎么模拟出这个数据格式呢,在请求体你可以看到有个词叫form-data
,这是个特殊的数据格式,也就是文件数据格式,js有这个api,是一个构造函数,代码如下
<input name="file" type="file" onchange="changeUpload(this.files[0])"/>
function changeUpload(file){
var formData = new FormData();
// 方式一我直接append装进去
formData.append("file", file);
// 方式二转成base64装进去,因为有时候是需要上传画布文件
// base64怎么获得查看后面的一期笔记
// formData.append("file", dataURLtoFile(base64,"filename.jsp"));
//还可以往formData里append更多数据
formData.append("name", "pdt1997");
$.ajax({
url:"xxxx",
type:"post",
data:formData,
//禁止jq修改我的提交数据,这个参数一定要加
processData: false,
contentType : false, // 不要设置Content-Type请求头
})
}
function dataURLtoFile(dataurl, filename) {
//将base64转换为文件
var arr = dataurl.split(','),bstr = atob(arr[1]),
n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:"image/jpeg"});
}
于是,我们用ajax成功模拟了form表单的文件提交!
post 和 application/json
我们上面一直说其他的请求头无法提交复杂数据类型的数据,现在对比下提交数据
$.ajax({
url:"xxxx",
type:"post",
data:{
obj:{ name:"name",age:18 },
arr:[0,1,2,3],
}
})
如果提交上面的数据是会被后端打死的,因为这么提交是拿不到数据的,需要改成json文件提交模式
$.ajax({
url:"xxxx",
type:"post",
contentType:"application/json",
//JSON.stringify() 一定要加
data:JSON.stringify({
obj:{ name:"name",age:18 },
arr:[0,1,2,3]
})
})
到这里jq的所有提交方式都讲完了,put,detele跟post是一样的
jq.ajax获取响应的几种写法自己去百度,他还有一个自动处理数据的dataType参数可以了解一下,还有上面的截图有个view-parsed的按钮,是浏览器自带的内容可读性优化的按钮,点一下数据会排列得好看一些
封装一个ajax,带进度条
var xhr = null;
if (window.XMLHttpRequest) {// code for Firefox, Opera, IE7, etc.
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {// code for IE6, IE5
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
// 获取上传进度
xhr.upload.onprogress = function(event) {
var percent = Math.floor(event.loaded / event.total * 100);
console.log(percent)
};
// 上传完成后的回调函数
xhr.onreadystatechange = function() {
if (xhr.status === 200) {
console.log(xhr.responseText);
} else {
console.log('上传出错');
}
};
//open设置请求方式和请求路径
xhr.open('POST', 'url');
//设置请求头
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded")
//send 发送
xhr.send(fd);
原生能读取上传进度,jq.ajax也行
$.ajax({
url:'xxxx',
....,
//获取ajaxSettings中的xhr对象,为它的upload属性绑定progress事件的处理函数
xhr: function(){
myXhr = $.ajaxSettings.xhr();
//获取ajaxSettings中的xhr对象,为它的upload属性绑定progress事件的处理函数
if(myXhr.upload){
//绑定progress事件的回调函数
myXhr.upload.addEventListener('progress',function(evt) {
var loaded = evt.loaded; //已经上传大小情况
var tot = evt.total; //附件总大小
var per = Math.floor(100 * loaded / tot); //已经上传的百分比
}, false);
}
//xhr对象返回给jQuery使用,固定写法
return myXhr;
},
success:function(){}
});
注意
一次ajax要请求成功,除了代码不出错
还要有几个条件
第一就是请求地址要存在,这是句废话
第二就是浏览器不跨域,(跨域的知识可以百度,也可以往后面找一篇跨域的笔记)
文件上传之上传文件夹
<input type="file" onchange="change(this.files)" accept="*/*" webkitdirectory />
function change(file){
console.log(file)
}
文件上传之拖拽上传
function handleDropover(event) {
event.stopPropagation();
event.preventDefault();
}
function handleDrop(event) {
event.stopPropagation();
event.preventDefault();
/***** 访问拖拽文件 *****/
const files = event.dataTransfer.files;
console.log(files);
/**********/
}
const div = document.querySelector("#container");
div.addEventListener("dragover", handleDropover);
div.addEventListener("drop", handleDrop);
文件上传之复制上传
这个查看富文本API笔记
文件上传之分片上传
分片上传还有断点续传,自行百度
function change(file) {
// 读取前5个字节的内容
const filePart = file.slice(start,end);
var fd = new FormData(); //构造FormData对象
fd.append('data',filePart);
fd.append('index', i);
}
文件上传之base64分片
直接把base64【字符串】切割成几份,或者转成file格式
function base64toBlob(base64) {
var arr = base64.split(',');
var bstr = atob(arr[1]);
var n = bstr.length;
var mime = arr[0].match(/:(.*?);/)[1];
var u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], {type: mime });
}
//将blob转换成file
function blobToFile(theBlob, fileName){
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
}
// 虽然console还是现实Blob,但是已经跟file是一样的了
var file = blobToFile(dataURLtoBlob(base64), "filename")
file.slice(start,end);
// 怎么把blob转成base64
// file怎么转,他就是怎么转,使用FileReader