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.responseTextconsole.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¶ms += 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=abcxhr.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.responseTextresult = 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].valueconst author = items[1].valueconst 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.responseTextconsole.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.responseTextconsole.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').filesif (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,属于新的APIvar 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格式
 
 
 - 设置基准路径
 
 
