AJAX学习
Ajax
的概念:
Ajax
用来实现客户端网页请求服务器的数据,当用户有操作时可以实时更新部分模块或者整个网页
先引入axios
库 官网:http://www.axios-js.com/
axios基本语法:
模板:
axios({
method: '',
url: '',
}).then((result) => {
//.then 用来指定请求成功之后的回调函数
// 形参中的result是请求成功之后的结果
});
then
方法(或回调函数)负责接受发过来的数据
属性区分大小写
axios GET 请求:
axios({
method: '请求的类型',
url: '请求的URL地址',
params: {id: 1, bookname: '红楼梦'}
// params用于传递参数,可选
}).then((result) => {})
Demo:为button
绑定一个click
事件并发送get
请求,注意params
可省
$('button').on('click', function() {
axios({
method: 'GET',
url: 'http://www.liulongbin.top:3006/api/getbooks',
params: {
id: 3
},
}).then(result => { //then控制请求成功
console.log(result.data.data);
}).catch(err => { //catch控制请求失败(扩展)
get
参数的本质就是把所有属性用=链接、&符号分隔、放到路径的最末尾(前面要加?)
Demo:
http://www.liulongbin.top:3006/getbook?id=1&bookname=红楼梦
注意不能有空格和中文等特殊字符,浏览器会对URL
的中文进行编码处理
编码和解码
axios的解构赋值
axios({
method: 'GET',
url: 'http://www.liulongbin.top:3009/api/getbooks'
}).then(({data: res}) => {
// 从 .then(fn) 回调函数的形参中,解构赋值出 data 属性,重命名为 res
console.log(res)
})
因为ajax
拿的参数中最重要的就是data
,在then
回调函数中通过对象解构把data
的参数赋值到一个res
的变量中(名称随意),然后对这个json
进行操作
then
返回的数据:
axios POST 请求:
POST
请求一定得有参数,因为POST就是推数据给服务器
axios({
method: 'POST',
url: 'http://www.liulongbin.top:3009/api/addbook',
data: { //post用的是data传递请求参数
bookname: '三体',
author: '刘慈欣',
publisher: '北京人民出版社'
},
}).then(({data: res}) => {
console.log(res);
})
请求报文和响应报文
客户端发请求给服务器,请求报文规定数据格式
服务器回数据,响应报文规定数据格式
注意的是响应码和状态码不同,下面展示的是响应码响应码由
http
协议制定,一般都约定俗成状态码不唯一,在接收到的数据中,可以由后端人员自己定义;就好比客户端无法请求数据大部分都返回
404
响应状态码表示与服务器端的通信请求是否成功,而状态码表示业务处理的状态,一般会由后端给你写在接口文档里,供需要时查阅
Ajax
表单数据提交
Ajax
表单数据提交一般的表单分为三个模块:表单标签form
、表单域(input
、textarea
、select
),表单按钮(submit
或reset
)
- 表单的作用就是收集数据
阻止默认行为:
$('form').on('submit', function (e) {
e.preventDefault();
})
为什么需要阻止默认行为?
默认的表单元素如果没有action
参数,也就是没有设置url
的话默认会刷新页面,设置了就会跳转,如果只是收集数据,我们应该阻止浏览器默认行为
Jquery 中的 serialize 方法:
$('form').serialize()
方法会拿表单中所有的带name
属性的数据,以a=1&b=2
(只是举例)这样的字符串数据类型发送请求
利用 serialize 请求数据:
$('form').on('submit', function(e) {
e.preventDefault();
axios.post('http://www.liulongbin.top:3009/api/form', $('form').serialize()
).then(({data: res}) => {
console.log(res);
})
})
细看请求包:
关注两个点就行:
application
后面是/x-www-form-urlencoded
(一般形式的get
和post
请求回的包都是json
类型)data
是以字符串形式传参的
使用 别名传参:
axios.get('http://www.liulongbin.top:3009/api/get').then(res => {
console.log(res.data);
})
axios.post('http://www.liulongbin.top:3009/api/post', {name: '123',}).then(res => {
console.log(res.data);
})
- 注意的是用
post
必须得有参数,而且第二个(data
)参数可以是{}
对象这种,也可以是json
或者FormData
等变量
其他别名(就是懒人语法/语法糖):
axios.delete(url,[]);
axios.put(url,[data{}])
axios.patch(url,[]);
全局配置根路径:
也是语法糖,但是有优点,项目里可以经常用,易于维护而不需要大量修改
方法①:
语法
axios.interceptors.request.use(function(config) {
config.url = '根路径url' + config.url
return config;
})
方法②:
拦截器
axios.interceptors.request.use(function(config) {
config.url = '根路径url' + config.url
return config;
})
axios
拦截器:
axios
拦截器:
在代码中: 拦截器配置在axios
文件的下面script
语句的前面
语法格式:
axios.interceptors.request / response.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
- 注意
use
中放两个函数就行,一个成功干什么,一个错误干什么
FormData:
FormData
是浏览器的一个Web Api
,它是一个原生DOM! FormData
配合ajax
,能够向浏览器发送multipart/form-data
编码格式的数据,一般用于文件上传
FormData
是一个构造函数,使用new
可以拿到FormData
对象
const fd = new FormData()
利用表单点击事件拿到FormData
对象(注意的是用的原生DOM)
let form = document.querySelector('form');
form.addEventListener('submit', function(e) {
e.preventDefault();
let fd1 = new FormData(form);
console.log(...fd1);
})
调用FormData
对象的append
(键,值)方法
fd.append(‘username’, ‘Lion’)
注意键名必须是字符串
使用FormData
请求一次数据:
const fd = new FormData;
fd.append('name', 'Lion');
fd.append('value', 'is man'
axios.post('http://www.liulongbin.top:3009/api/formdata', fd).then(({data: res}) => {
console.log(res);
})
细看请求包,确认传参成功:
数据交换原理
JSON数据类型:
全称:JavaScriptObjectNotation
可以理解为一个键值对都是字符串的数据格式,在C++
、python
等多种语言中都有这种数据类型
服务器和客户端常用的两种数据交换格式为:XML和JSON;早期则是XML、目前主流格式为JSON
JSON数据的格式:
可以是: 对象、数组、布尔值、null
不可以是: undefined
、function
JSON语法要求`:
- 属性名必须使用双引号
- 不允许单引号表示字符串
- 不能写注释
- 最外层必须是对象或者数组
JSON 中 Ajax 常用方法:
反序列化: JSON
格式转JS
数据
JSON.parse()
序列化:JS
数据转JSON
格式;为前一个方法的逆运算
JSON.stringgify()
Ajax底层 ==> XMLHttpRequest
- 什么是
XMLHttpRequest
?
是浏览器内置的一个构造函数(也就意味着它是原生的);也是ajax
的核心对象
axios
中的get
、post
,包括axios
本身都是基于它(简称XHR
)封装出来的
不用axios
,自己用XHR
也是可以给服务器发包的
分为四步:
- 实例化
xhr
- 调用
xhr.open()
指定请求方法 - 调动
xhr.send()
发送数据 - 监听
load
事件并用xhr.response()
方法接受响应报文
使用xhr
发送GET
:
document.querySelector('button').onclick = function() {
const xhr = new XMLHttpRequest();
xhr.open('GET','http://www.liulongbin.top:3009/api/get');
xhr.send();
xhr.addEventListener('load', function() {
console.log(JSON.parse(xhr.response));
//接受过来的数据是纯字符串,转换成JSON更清晰
})
}
使用xhr
发送POSt
:
document.querySelector('button').onclick = function() {
const xhr = new XMLHttpRequest();
xhr.open('POST','http://www.liulongbin.top:3009/api/post');
xhr.send('name: David');
xhr.addEventListener('load', function() {
console.log(JSON.parse(xhr.response));
})
}
注意:send默认只发送字符串格式的参数,除非传参FormData变量或者setRequestHeader手动指定报头
也可以使用类似HTML表单标签的方式设置请求类型发送POST
:
JSON:
document.querySelector('button').onclick = function() {
const xhr = new XMLHttpRequest();
xhr.open('POST','http://www.liulongbin.top:3009/api/post');
xhr.setRequestHeader('content-type', 'application/json');
//大小写无所谓,浏览器会做处理
xhr.send(`{"name": "David", "age": "18"}`);
//JSON必须键值对都用双引号
xhr.addEventListener('load', function() {
console.log(JSON.parse(xhr.response));
})
}
Request Headers:
字符串(a=1&b=2这种):
document.querySelector('button').onclick = function() {
const xhr = new XMLHttpRequest();
xhr.open('POST','http://www.liulongbin.top:3009/api/post');
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
//大小写无所谓,浏览器会做处理
xhr.send('name=David&age=18');
//字符串参数
xhr.addEventListener('load', function() {
console.log(JSON.parse(xhr.response));
})
}
Request Headers:
注意:如果漏写&z或者其他符号就会被浏览器认为是单个属性(键名),而就不是收到如上图所示的键值对形式了
FormData:
document.querySelector('button').onclick = function() {
const fd = new FormData();
fd.append('name', 'David');
fd.append('age', '18');
const xhr = new XMLHttpRequest();
xhr.open('POST', 'http://www.liulongbin.top:3009/api/post');
xhr.send(fd);
//无需设置setRequestHeader, 默认转换
xhr.addEventListener('load', function() {
console.log(JSON.parse(xhr.response));
})
Request Headers:
注意:load事件是异步任务,位置可以随意放置
Jquery 中的 Ajax:
Jquery
中对于ajax
封装了三个方法:
$.get() | $.post() | $.ajax()
- 与
axios
有一些不同 - (因为
axios
是基于Jquery
的ajax方法改进而成的)
$.get():
$.get('http://www.liulongbin.top:3009/api/getbooks',{id:2},
function(res) {
console.log(res);
})
$.post()
$.post('http://www.liulongbin.top:3009/api/addbook',{
bookname: 'djy', author: 'dsy', publisher: '谁知道'
}, function(res) {
console.log(res);
})
$.ajax()
$.ajax({
method:'post',
url: 'http://www.liulongbin.top:3009/api/addbook',
data: {
bookname: 'dsypig',
author: 'dsypig',
publisher: '谁知道'
},
success: function(res) {
console.log(res);
}})
区分:
then
被success
替代success
的形参不需要结构,直接返回值的data
部分- 请求参数不似
axios
不分区get
的params
和post
的data
jquery
中的拦截器必须自己手动设置,跟axios
的不为同一个!
利用$ajax.()实现上传文件(或者发送FormData对象)
jQuery
中的ajax
比较特殊,上传文件(或者说发送FormData
对象)必须带两个参数:
contentType: false //取消默认设置文件头信息
processData: false //取消对文件默认的编码
利用$ajax.()实现CORS跨域
$ajax({
dataType: 'jsonp'
//json | text | html | xml | script
})
dataType
:改变底层的请求方式和请求报头,不再让它使用XHR
、而是使用script
标签发包(script
标签不与同源策略冲突)并且返回值是jsonp
格式(也可以指定其他返回格式)
返回值格式:
同源策略:
- 什么是同源?
同源值得是两个URL
地址具有相同的协议、主机名、端口号
如果不同源直接发包,则是跨域请求
http的默认端口是80、https是443 默认不写浏览器也能识别
- 为什么会有跨域?
浏览器的安全策略:
它不允许非同源的URL
进行资源交互
跨域的请求会被放行,但是响应包会被拦截
跨域的解决方案:
方案 | 诞生的时间 | 方案来源 | 优点 | 缺点 |
---|---|---|---|---|
JSONP | 出现较早 | 民间 | 兼容性好 | 仅支持get请求 |
CORS | 出现较晚 | W3C | 支持五种常见请求方式 | 兼容性 |
CORS是跨域的主流技术解决方案,但是面试官喜欢JSONP
深入:
CORS
用到了XMLHTTPRequest
对象,是纯正的ajax请求
JSONP
没有用XMLHTTPRequest
对象,是偏方
只要涉及和用到了XMLHTTPRequest
,就是ajax
请求
底层:
CORS
(后端方案、我暂时不研究):
JSONP
(需要后端配合的方案):
JSONP
在底层是用到了script
标签的src
属性,script
标签的src
属性不受同源策略限制,与之类似的还有a标签的跳转、img
的src
,它是把非同源的src
请求到本地然后执行
<script src="http://www.liulongbin.top:3009/api/jsonp?callback=showInfo&name=david">
</script>
<script>
function showInfo(res) {console.log(res);}
</script>
因为script
标签只能发送get
请求,而且在工作中前端和后端要约定一致一个函数名,对不上会出问题,还可以在标签里写callback
回调函数的形式告诉后端要返回什么样的函数名、以及传少量的字符串参数
防抖和节流
防抖是指频繁触发某个操作只执行最后一次
实现:
- 定义一个延时器
- 事件开始之前清除延时器
- 触发事件后延迟一段时间,如果没有继续被触发,则执行回调函数;如果又被触发,重新计时
节流是指单位时间内某个操作只执行触发一次
实现:
执行函数时,if
判断某种状态或者计时,如果未满足条件或者计时器没有结束则return
;如果条件为真或者到单位时间设置flag
为true
;继续执行下面的函数