Ajax-day03
原生Ajax
Ajax Asynchronous Javascript and Xml 异步的JavaScript和Xml
原生Ajax基本用法
- 浏览器已经实现了Ajax发送请求的技术XMLHttpRequest(2005之后)
- 基本使用步骤get post 模板
- 创建xhr对象
- 调用xhr.open()方法准备参数
- 调用xhr.send()方法执行发送动作
- 监听xhr.onreadystatechange事件,用于获取服务器返回数据
// 1、创建xhr实例对象
var xhr = new XMLHttpRequest()
// 2、准备发送请求的相关参数
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks')
// 3、执行发送请求的动作
xhr.send(null)
// 4、指定回调函数,用于处理服务器的返回
xhr.onreadystatechange = function () {
// 该函数是服务器返回数据后触发,该方法不仅仅触发一次
if (xhr.readyState === 4 && xhr.status === 200) {
// 如果上述两个条件都满足,就可以获取服务器返回的正常数据
// ret 是普通字符串
var ret = xhr.responseText
console.log(ret)
console.log(typeof ret)
}
}
总结:使用原生Ajax发送请求很繁琐。
xhr对象详解-请求参数
- get请求方式传参
- url地址查询字符串方式传递参数
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks?id=1&author=吴承恩')
var param = '?id=1&author=吴承恩'
// params = encodeURI(params)
xhr.open('get', 'http://www.liulongbin.top:3006/api/getbooks' + param)
- url编码(url如果传递参数本身是不支持中文,所以get传参时需要编码,如果不进行编码,那么后端可能得不到正确的数据)
- encodeURI() 编码函数
- decodeURI() 解码函数
var str = '黑马程序员'
var str1 = encodeURI(str)
console.log(str1)
var str2 = decodeURI('%E9%BB%91%E9%A9%AC')
console.log(str2)
- post请求方式传参
- 必须设置请求头
- 必须在send方法调用前设置请求头
// 设置 Content-Type 请求头(告诉服务器前端传递过去的数据格式)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// 调用 send 函数
xhr.send('bookname=水浒传&author=施耐庵&publisher=上海图书出版社')
xhr对象详解-响应状态
- readyState
- 如果该状态值为4表示服务器已经完全把数据返回了,此时可以获取后台的数据
- 仅仅表示数据已经得到,但是正确与否不确定
- status
- http协议的状态:如果status是200表示数据正常,否则表示数据不正常
// readyState状态值是4表示服务器数据已经完全返回
// status的值是200表示服务器返回的数据是正常的
// if (xhr.readyState === 4 && xhr.status === 200) {
// // 如果这两个条件都成立,就可以获取服务器数据了
// var res = xhr.responseText
// console.log(typeof res)
// } else {
// alert(xhr.responseText)
// }
// ---------------------------------------------------
// 考虑异常情况,需要用这种写法
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 成功获取服务器数据
var res = xhr.responseText
} else {
alert('服务器发生错误')
}
}
总结
- xhr.readyState===4表示后端已经把数据完整返回,但是正常与否不确定
- xhr.status===200表示服务器返回的数据是正常的,否则是异常的
xhr对象详解-响应数据
- 数据格式分析
- xml (类似于html格式,标签包裹数据)
- 缺点1:冗余数据比较多,不方便网络传输
- 缺点2:不方便前端解析
- json(本质上是字符串,但是有规则)
- 解决XML的两个问题
- xml (类似于html格式,标签包裹数据)
- JSON基本规则(JSON是字符串的一种格式)
- 数据结构为键值对 uname: ‘lisi’
- key 必须是使用英文的双引号包裹的字符串 “uname”:”lisi”
- 字符串类型的值必须使用双引号包裹 “uname”:”lisi”
- JSON 中不能写注释
- JSON 的最外层必须是对象或数组格式
- 不能使用 undefined 或函数作为 JSON 的值
- value 的数据类型可以是数字、字符串、布尔值、null、数组、对象6种类型
- JSON格式转换(JSON和对象之间的关系)
- 对象转字符串 JSON.stringify()
- 字符串转对象 JSON.parse()
var jsonStr = '{"a": "Hello", "b": "world"}'
// 把JSON字符串转成对象
var obj = JSON.parse(jsonStr)
console.log(obj)
// 把对象转成JSON字符串
var obj2 = { a: 'hello', b: 'world', c: false }
var str = JSON.stringify(obj2)
console.log(str)
- Ajax返回的结果处理
- xhr.responseText本身是字符串
var obj = JSON.parse(xhr.responseText)
总结:
- JSON格式的具体规范
- JSON字符串与对象之间的转换
模仿$.ajax封装函数
- 基本结构分析:回调函数参数如何得到
- 参数处理:支持get和post
- 响应数据处理:转换为对象
// 自己定义这样一个方法,可以实现$.ajax类似的功能
// 那么,可以任务这就是jQuery方法的源代码
function ajax(option) {
// console.log(option.type)
// console.log(option.url)
// console.log(option.data.id)
// console.log(option.success)
// data可以认为是后端返回的数据
// 1、创建xhr实例对象
const xhr = new XMLHttpRequest()
// 2、准备请求参数
// http://www.liulongbin.top:3006/api/getbooks?id=1&author=abc
// 需求:把对象转换为查询字符串
/*
{
id: 1,
author: 'abc'
}
上述对象需要转换为如下的格式
id=1&author=abc
*/
let params = ''
for (const key in option.data) {
// id=1&author=abc&
params += key + '=' + option.data[key] + '&'
}
if (params.length > 0) {
// 去掉最后一个&符号
if (params.lastIndexOf('&') === params.length - 1) {
// 最后是&符号,那么就去掉
params = params.substring(0, params.length - 1)
}
}
// 只有get请求时,才拼接到URL地址之后
// toUpperCase方法的作用:把字符串转换为大写
if (option.type.toUpperCase() === 'GET') {
option.url += '?' + encodeURI(params)
}
// http://www.liulongbin.top:3006/api/getbooks?id=1&author=abc
xhr.open(option.type, option.url)
// 3、执行发送请求的动作
// 如果是post请求参数的话,需要使用send发送数据给服务器
if (option.type.toUpperCase() === 'POST') {
// post请求必须设置请求头
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send(params)
} else {
// get请求
xhr.send(null)
}
// 4、监听服务器返回的数据
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取后端返回的原始数据
let result = xhr.responseText
result = JSON.parse(result)
// const result = '{"uname": "lisi"}'
option.success(result)
}
}
}
}
ajax({
type: 'post',
url: 'http://www.liulongbin.top:3006/api/addbook',
data: {
author: 'nihao1',
bookname: 'hello',
publisher: 'abc'
},
success: function (ret) {
console.log(ret.msg)
}
})
总结
- success是如何获取数据的
- Ajax发送请求的基本流程
- get请求参数如何传递
- post请求参数如何传递
- 返回的结果要转换成对象
原生Ajax升级版
XHR2.0介绍
- 旧版的缺点
- 仅仅支持文本数据传输,无法上传文件(早期文件上传基于Flash)
- 传送数据没有进度提示
- 新版功能
- 可以使用FormData传递表单数据
- 可以上传文件
- 传输数据时进行提示
FormData基本用法
- FormData是标准的js构造函数(WebAPI)
- FormData作用是啥?传递post请求参数(一般数据来源于表单)
- 如何知道FormData实例对象有几个方法?看官网
FormData相关方法
- fd.append 添加数据
- fd.get 获取数据
- fd.has 判断是否有数据
- fd.delete 删除数据
var fd = new FormData()
fd.append('msg', 'nihao')
// var v = fd.get('msg')
// fd.delete('msg')
var f = fd.has('msg')
console.log(f)
总结:
- FormData用于post提交参数
- FormData提供相关的方法用来操作参数数据
用法一:
- 造函数不传参使用append方法添加参数
- 注意:不需要设置请求头
const btn = document.getElementById('btn')
btn.onclick = function (e) {
e.preventDefault()
// 1、创建xhr实例对象
const xhr = new XMLHttpRequest()
// 2、准备请求参数
// 如下的接口专门用于测试FormData数据的,
// 该接口的功能是:提交什么数据就返回什么数据
xhr.open('post', 'http://www.liulongbin.top:3006/api/formdata')
// 3、执行发送请求动作
const items = document.getElementsByTagName('input')
const bookname = items[0].value
const author = items[1].value
const publisher = items[2].value
// console.log(bookname, author, publisher)
const fd = new FormData()
fd.append('bookname', bookname)
fd.append('author', author)
fd.append('publisher', publisher)
// FormData数据格式是独立的一种格式multipart/form-data
// 这种格式的数据,后端需要额外处理才可以得到这种数据
xhr.send(fd)
// 4、监听服务器返回的结果
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常数据
const ret = xhr.responseText
console.log(ret)
}
}
}
}
总结:
- FormData数据格式是独立的一种格式multipart/form-data
- 这种格式的数据,后端需要额外处理才可以得到这种数据
- 不可以设置请求头,默认自动设置为multipart/form-data
用法二:
- 这种方式,表单的输入域必须提供name属性
// 通过 DOM 操作,获取到 form 表单元素
var form = document.querySelector('#form1')
// 创建 FormData,快速获取到 form 表单中的数据
var fd = new FormData(form)
// 也可以一块使用append继续追加数据
fd.append('info', 'abc')
// 发送请求
xhr.send(fd)
总结
- 表单的输入域必须提供name属性
- 可以和append结合使用
FormData文件上传
文件上传的本质:把本地的文件传递到服务器并进行存储,然后返回文件的URL
- UI布局需要用到file标签
- 判断是否选择文件
- 向FormData中追加文件
- 使用xhr发起上传文件请求
- 监听onreadystatechange事件
<form id='upload'>
<!-- 添加multiple属性表示支持多选,默认仅仅可以选择一个文件 -->
<input type="file" id="myfile" multiple>
<input type="submit" value="点击">
</form>
// 基于FormData上传文件
const form = document.getElementById('upload')
form.onsubmit = function (e) {
e.preventDefault()
// 1、创建xhr实例对象
const xhr = new XMLHttpRequest()
// 2、准备请求参数
xhr.open('post', 'http://www.liulongbin.top:3006/api/upload/avatar')
// 3、执行发送请求动作
const file = document.getElementById('myfile')
console.log(file.files)
const fd = new FormData()
// file表示input类型是file的标签DOM对象,他有一个属性files表示选中的文件列表
fd.append('avatar', file.files[0])
xhr.send(fd)
// 4、监听服务器返回的结果
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// 获取正常数据
const ret = xhr.responseText
console.log(ret)
}
}
}
}
- 直接基于Form表单也可以进行文件上传
<form>
<input type="file" name="avatar" id="myfile">
<button id="btn">点击</button>
</form>
// 通过FormData上传文件
var form = document.querySelector('form')
var fd = new FormData(form)
总结
- 文件上传需要通过FormData进行
- 可以直接把文件append进去
- 也可以通过new FormData时直接把表单DOM放到构造函数的参数中
- file标签的multiple属性用于控制多文件上传
基于jQuery上传文件
需求:基于jQuery的方式上传文件
<form id='upload'>
<!-- 添加multiple属性表示支持多选,默认仅仅可以选择一个文件 -->
<input type="file" name='avatar' id="myfile" multiple>
<input type="submit" value="点击">
</form>
<script src="lib/jquery.js"></script>
<script>
// 基于jQuery上传文件
$('#upload').submit(function (e) {
e.preventDefault()
console.log('hello')
const fd = new FormData()
fd.append('avatar', $('#myfile').get(0).files[0])
$.ajax({
type: 'post',
url: 'http://www.liulongbin.top:3006/api/upload/avatar',
// 默认Ajax提交的数据是application/x-www-form-urlencoded
// 但是FormData的格式是multipart/form-data
// false表示不把数据的格式进行转换,而是保留FormData的原始格式
processData: false,
// false表示不采用默认的提交数据类型,而是采用FormData的格式
contentType: false,
data: fd,
success: function (ret) {
console.log(ret)
}
})
})
</script>
总结:
- $.ajax默认提交的数据格式是 application/x-www-form-urlencoded (uname=lisi&age=12)
- 为了上传文件,需要定制提交的数据格式
- processData: false, 表示不把数据的格式进行转换,而是保留FormData的原始格式
- contentType: false, 表示不采用默认的提交数据类型,而是采用FormData的格式
上传文件进度提示
上传大一点儿的文件需要一些时间,这段时间最好给一个提示,提升用户体验
- xhr.upload.onprogress = function (e) {}
- 监听文件上传进度
- xhr.upload.onload = function () {}
- 监听文件上传完成事件
<progress id="pg" max="100" value="0"></progress>
<!-- bootstrap 中的进度条 -->
<div class="progress" style="width: 500px; margin: 15px 10px;">
<div class="progress-bar progress-bar-striped active" style="width: 0%" id="percent">
0%
</div>
</div>
// 获取到用户选择的文件列表
var files = document.querySelector('#file1').files
if (files.length <= 0) {
return alert('请选择要上传的文件!')
}
var fd = new FormData()
// 将用户选择的文件,添加到 FormData 中
fd.append('avatar', files[0])
var xhr = new XMLHttpRequest()
// 监听文件上传的进度
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
// 判断文件是否正在上传
// 已经上传的大小/文件的总大小 = 进度
var rate = Math.ceil((e.loaded / e.total) * 100)
// 把进度数据应用到进度条上
var bar = document.getElementById('percent')
// 修改进度条的进度
bar.style = 'width: '+ rate +'%'
// 进度条显示的文字进度
bar.innerHTML = rate + '%'
}
}
// 监听文件上传完成的动作
xhr.upload.onload = function () {
// 文件上传完成后触发,修改进度条颜色
var bar = document.getElementById('percent')
// DOM元素的classList可以操作类名
// 删除已有的类名
bar.classList.remove('progress-bar-striped')
// 添加一个新的类名
bar.classList.add('progress-bar-success')
}
xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd)
总结:
- 监听文件上传的进度 e.loaded/e.total
- 监听文件上传的完成
基于jQuery的方式监听上传进度
技术采用jQuery,需要控制上传文件的进度
// 提供一种定制原生Ajax对象的方式
xhr: function () {
const xhr = new XMLHttpRequest()
xhr.upload.onprogress = function (e) {
if (e.lengthComputable) {
const percent = Math.floor(e.loaded / e.total * 100) + '%'
$('#percent').css('width', percent).html(percent)
}
}
xhr.upload.onload = function () {
$('.progress').hide()
}
return xhr
},
// ---------------------------------
let xhr = new XMLHttpRequest()
if (option.xhr) {
xhr = option.xhr()
}
总结:xhr的函数内部,可以创建一个新的原生Ajax的实例对象,如果内部的默认xhr对象
总结
- 关于FormData
- FormData的作用:post提交数据给服务器
- FormData的基本使用
- fd.append 添加数据
- fd.get 查看数据
- 应用场景:直接提交表单数据;上传文件
- new FormData时,构造函数没有参数,而是通过append动态添加数据
- new FormData时,构造函数传入一个参数(参数是form标签DOM对象),前提条件表单输入域必须有name属性,属性值由后端接口决定
- 文件上传也是基于FormData实现
- 手动获取file标签的文件数据,然后append进入FormData里面
- 直接在new FormData时,把form标签的DOM元素添加到构造函数里面即可
- 基于Ajax的xhr2特性上传文件 xhr.send(fd)
- 监听文件上传的进度
- xhr.upload.onprogress 监听上传进度
- xhr.upload.onload 监听上传完成
axios
axios介绍
- axios 是一个专门用于调用后台接口的js库,后续Vue和React环境都可以使用它
- 支持客户端发送Ajax请求
- 支持服务端Node.js发送请求
- 支持Promise相关用法(解决回调地狱问题)
- 支持请求和响应的拦截器功能(登录时会用到)
- 可以手动取消请求
- 自动转换JSON数据(JSON.parse(res))
- 可以更加安全的处理请求
基本用法
- 发送请求通过axios.get
- 获取结果通过then方法
- 对于返回的结果来说,axios会在后台返回的数据外面包裹一层data属性
- 假如后台返回的数据是 {status: 200, msg: ‘返回成功’,data: [{}]}
- 那么axios实际得到的数据是 {data: {status: 200, msg: ‘返回成功’,data: [{}]}}
- 对于返回的结果来说,axios会在后台返回的数据外面包裹一层data属性
axios.get('http://www.liulongbin.top:3006/api/getbooks')
.then(function (res) {
// 这里用于获取服务端返回的结果
// res.data中的data是由axios规定的名称,表示从后台得到的数据
console.log(res.data)
})
axios的get用法
- get 请求数据并传递参数
- get方法第二个参数是配置对象 axios(url, [, config])
- params 用于传递get参数,它的值为对象,对象中用于传递键值对形式参数
- 发送请求时,params中的参数会自动拼接到url中进行发送
- params 是专门用于get请求
- get方法第二个参数是配置对象 axios(url, [, config])
// 上述传参方式不太方便
axios.get('http://www.liulongbin.top:3006/api/getbooks', {
// params名称是否固定?是的,是axios的规定
params: {
id: 1,
bookname: 'nihao'
}
}).then(function (res) {
// 这里用于获取服务端返回的结果
console.log(res)
})
// api/get 接口专门测试get请求,请求参数是什么,就返回什么
axios.get('http://www.liulongbin.top:3006/api/get', {
// params名称是否固定?是的,是axios的规定
params: {
id: 1,
bookname: 'nihao',
publisher: 'abc'
}
}).then(function (res) {
// 这里用于获取服务端返回的结果
console.log(res)
})
总结:
- get传参可以直接在url地址中拼接参数,不建议这样做
- 可以基于axios提供的参数params传递get请求参数
axios发送post请求
- post请求数据传递
- 传统的表单提交的数据格式 content-type: application/x-www.form-urlencoded
- 后端一般默认支持这种提交的参数格式
- post请求参数如果是对象,默认发送的是json形式的参数(content-type: application/json)
- 这种方式的请求参数也需要后台提供支持
- 传统的表单提交的数据格式 content-type: application/x-www.form-urlencoded
// axios发送post请求 post(url[, data[, config]])
// post 参数一:请求地址
// post 参数二:表示请求参数,可选的
// post 参数三:表示配置对象,可选的
// 传统的表单提交的数据格式 content-type: application/x-www.form-urnencoded
// 如下的请求方式,默认发送的是json形式的参数(content-type: application/json)
// 这种方式的请求参数也需要后台提供支持
axios.post('http://www.liulongbin.top:3006/api/post', {
uname: 'lisi',
pwd: '123'
})
.then (function (res) {
console.log(res)
})
- 强制采用content-type: application/x-www.form-urnencoded 请求参数格式
// axios发送post请求 post(url[, data[, config]])
// post 参数一:请求地址
// post 参数二:表示请求参数,可选的
// post 参数三:表示配置对象,可选的
// 强制post发送这种格式请求参数 content-type: application/x-www-form-urlencoded
// 类似于FormData的用法,专门用于参数传递
// URLSearchParams 是一个标准的构造函数,类似于FormData,属于新的API
var fd = new URLSearchParams()
fd.append('uname', 'lisi')
fd.append('pwd', '123')
// 发送请求时会转换为如下格式
// uname=lisi&pwd=123
// 这种格式的请求参数,服务器一般默认都支持
axios.post('http://www.liulongbin.top:3006/api/post', fd)
.then (function (res) {
console.log(res)
})
总结
- post请求默认发送的数据格式是 application/json
- post请求也可以强制发送 application/x-www.form-urlencoded 格式数据(基于URLSearchParams)
- 前端提交给后端的数据格式(具体用那种格式由后端决定)
- application/x-www-form-urlencoded
- multipart/form-data
- application/json
另一种用法
- axios作为方法使用
- 支持各种请求方式
- 支持各种方式传参
// axios更加通用的调用接口方式
// axios({
// // 表示请求方式
// method: 'get',
// url: 'http://www.liulongbin.top:3006/api/get',
// params: {
// id: 1,
// uname: 'lisi'
// }
// }).then(function (res) {
// console.log(res)
// })
// 发送请求参数 json格式
// axios({
// // 表示请求方式
// method: 'post',
// url: 'http://www.liulongbin.top:3006/api/post',
// data: {
// id: 123,
// uname: 'lisi',
// age: 12
// }
// }).then(function (res) {
// console.log(res)
// })
// 发送请求参数 form格式
// var fd = new URLSearchParams()
// fd.append('uname', 'lisi')
// fd.append('pwd', '123')
// axios({
// // 表示请求方式
// method: 'post',
// url: 'http://www.liulongbin.top:3006/api/post',
// data: fd
// }).then(function (res) {
// console.log(res)
// })
总结
- axios既可以发送get请求,也可以发送post请求
- post请求默认发送json格式数据,也可以基于URLSearchParams强制发送www格式数据
全局默认配置
- 配置基准URL地址
- 做项目时,基准一般配置一次即可,发送请求时检修url后面的路径即可
axios.defaults.baseURL = 'http://www.liulongbin.top:3006/'
axios.get('api/get?id=1').then(function (res) {
console.log(res)
})
总结
- 设置基准路径,可以简化发送请求时的路径
- 方便上线时随时调整基准路由(只有一个地方有基准路径)
总结
- 模仿$.ajax封装原生Ajax
- success如何获取结果
- Ajax的基本请求流程
- 创建实例对象
- 准备请求参数 xhr.open
- 执行发送动作 xhr.send
- 监听返回的结果 xhr.onreadystatechange
- get请求参数处理
- post请求参数处理
- 返回的结果需要转换为对象
- FormData
- 作用:post提交参数
- 熟悉基本用法
- 提交表单数据
- 先new在append
- 直接new时传入form元素
- 两者可以结合使用
- 利用它进行文件上传
- 先new在append
- 直接new时传入form元素
- 文件上传的进度监控
- xhr.upload.onprogress
- xhr.upload.onload
- jQuery方式上传文件并处理进度监控
- axios
- 这是一个专门发送请求的js库
- 基本使用(获取数据时需要需要ret.data)
- get请求传递参数,需要使用params属性
- post请求直接通过axios.post参数二传递对象即可
- 默认请求参数格式为json
- 可以强制设置为www格式
- 通用请求方法axios()
- 支持get请求,需要params属性
- 支持post请求,需要data属性
- 默认是json格式
- 可以指定为www格式
- 设置基准路径