AJAX学习 ---- axios体验
前言:AJAX是浏览器和服务器进行数据通信的技术

一、先使用 axios 第三方库,与服务器数据进行数据通信
为什么要使用该第三方库,不直接使用底层原理进行呢?
- 基于XMLHttpRequest封装、代码简单、月下载量在14亿次
- Vue、react项目中都会用到axios
axios是怎么进行操作的呢?
axios作为第三方库,在使用时需要将该库相关的 js 代码引入到自身网页中,然后会得到一个全局的 axios函数,那么就能调用该函数了。(注意:① axios函数中传入配置对象 ② 用 .then回调函数接收结果,并做后续处理)
1.axios使用:
需求:请求目标资源地址,拿到省份列表数据,显示到页面
目标资源地址:http://hmajax.itheima.net/api/province

可以看到浏览器中直接访问返回的是对象结构的 json 字符串,在该对象中有两组 key和value,一对是message,一对是list
补充:之所以是 axios({ })这样子的形式,是因为 axios 是一个函数,函数调用的方式就是 函数(参数1,参数2, ...)而之所以这个里边还有花括号,是因为传入的是一个对象,所以用花括号将对象括起来
接下来从 result 对象中拿到省份列表数据

- 第一次打印出整个result对象
- 第二次打印出省份列表
- 第三次数组中用 <br> 作为分隔符将所有元素合并成一个字符串
- 把合成的字符串设置到HTML元素的 innerHTML中,浏览器会把它当作HTML标签进行解析,<br>真的会换行

2、认识URL
定义:统一资源定位符,俗称网页地址,简称网址,用于访问网络上的资源。
例 https://www.baidu.con/index.html,该地址定位到的是网页资源。
https://www.itheima.com/images/logo.png ,图片资源
http://hmajax.itheima.net/api/province ,数据资源
http://hmajax.itheima.net/api/province
组成:
http:// 协议
hmajax.itheima.net 域名/api/province 资源路径
①http协议:超文本传输协议,规定浏览器和服务器之间传输数据的格式

②域名:标记要访问的服务器在互联网中方位。例如 baidu.com就是百度服务器

③资源路径:标记资源在服务器下的具体位置

获取 - 新闻列表
需求:使用axios从服务器拿到新闻列表数据
目标资源地址:http://hmajax.itheima.net/api/news
在此之前已经学习了引入 axios 第三方库进行获取 服务器数据,现在用来获取新闻数据也是一样的使用方法

补充:
axios( )是调用函数axios,那么axios( ).then( )是不是就说明 then是axios函数的方法呢?
答:不是,then是 promise 对象的方法,况且 只有对象里边才能包含方法,方法就是函数,函数里边怎么能包含函数呢。
promise是 javascript中用于处理异步操作的一个 内置对象,它提供了两个重要方法。
.then(onFulfilled, onRejected?) 当 Promise 成功时(fulfilled),执行
onFulfilled函数,你在这里处理返回的数据
.catch(onRejected) 当 Promise 失败时(rejected),执行这个函数,你在这里处理错误
// 1. axios(...) 是函数调用,返回一个 Promise
const promise = axios({method: 'get',url: '/api/data'
});// 2. then 是 promise 对象的方法
promise.then(function (response) {console.log('请求成功', response.data);
}).catch(function (error) {console.error('请求失败', error);
});//或简写为一行链式调用
axios({method: 'get',url: '/api/data'
}).then(function (response) {console.log(response.data);
}).catch(function (error) {console.error(error);
});
3、URL查询参数
定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据
语法:http://xxxx.com/xxx/xxx?参数名1=值1 & 参数名2 = 值2(URL之后用 ?引出特定的参数,多个参数时 用 & 进行连接)
axios - 查询参数
语法: 使用 axios 提供的 params 选项注意:axios在运行时把参数名和值,拼接到 url?参数名= 值
城市列表:http://hmajax.itheima.net/api/city?pname=河北省
axios({url:'目标资源地址',params:{参数名:值}}).then(result => {//对服务器返回的数据做后续处理})
打印出了 axios 的结果对象,同样是在 data 属性中看到了后端给出的 河北省 对应城市列表:

如果想要将该城市呈现在页面中,那么就需要一个容器,也就是html标签,获取该标签之后将内容插入到标签中。同样,需要将数组转换成字符串,使用 join方法,并且使用 <br> 标签作为分隔符,在插入时使用 innerHTML 进行插入时识别 标签,继而进行换行

地区查询
需求:根据树入的省份名字和城市名字,查询地区并渲染列表
首先:确定URL网址和参数说明
- 查询某个省内某个城市的所有地区:http://hmajax.itheima.net/api/area
- 参数:
pname:省份名字或直辖市名字,比如北京、福建省、辽宁省...
cname:城市名字,比如北京市、厦门市、大连市...
主体大概框架:一个大的 div 容器 。然后是一个form标签包含两个并列同类 mb-3 col 的 div容器,这两个标签中都包含类为 form-label的 label 标注标签以及 input树入框获取输入的数据。与form表单并列的是button 按钮。接着是 li 无序列表。
补充:input输入框中属性作用 , value :还未输入时默认值(预填入),name:是该输入框的一个名称标识,用于在提交表单时告诉服务器 ”这个输入框的值,对应的是名为 city 的字段“

给按钮添加点击事件,点击之后获取输入框中输入的省份和城市名字,基于axios 将输入框中的省份和城市传到服务器上,然后把服务器返回的省份城市列表数据用 map 遍历,给每个把每个数据都添加到 li 标签中。
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>地区查询</title><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"><style>:root {font-size:15px;}body {padding-top:15px;}</style>
</head>
<body><div class="container"><form class="row" id="editForm"><!-- 输入省份名字 --><div class="mb-3 col"><label class="form-label">省份名字</label><input type="text" value="北京" name="province" class="form-control province" placeholder="请树入省份名称"></div><!-- 输入城市名字 --><div class="mb-3 col"><label class="form-label">名字城市</label><input type="text" value="北京市" name="city" class="form-control city" placeholder="请输入城市名字"></div></form><button type="button" class="btn btn-primary sel-btn">查询</button><br><p>地区列表:</p><ul class="list-group"><li class="list-group-item">东城区</li></ul></div><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>/*获取地区列表: http://hmajax.itheima.net/api/area查询参数:pname: 省份或直辖市名字cname: 城市名字*/// 目标: 根据省份和城市名字, 查询地区列表// 1. 查询按钮-点击事件document.querySelector('.sel-btn').addEventListener('click',() => {//2.获取省份和城市名字let pname = document.querySelector('.province').valuelet cname = document.querySelector('.city').value//3.基于axios请求地区列表数据axios({url:'http://hmajax.itheima.net/api/area',params:{pname,cname}}).then(result => {//4.把数据转li标签插入到页面上let list = result.data.listconsole.log(list)//遍历数组中每个元素,这里用areaName表示每个元素,将每个元素包含在li标签中let theLi = list.map(areaName => `<li class="list-group-item">${areaName}</li>`).join('')console.log(theLi)//innerHTML能直接识别标签,在网页中显示出小圆点document.querySelector('.list-group').innerHTML = theLi})})</script></body>
</html>
补充:里边的 axios 请求,用params写查询参数时,格式应当是 属性名:变量名,但是这里的属性名和变量名相同了,所以只用写一个就行。(今后的变量名可尽量写跟后端给出的属性名一样,那样就只用写出一个了)

下面查询了北京的地区列表:

4.常用请求方法
请求方法:对服务器资源,要执行的操作
| 请求方法 | 操作 |
|---|---|
| GET | 获取数据 |
| POST | 提交数据 |
| PUT | 修改数据(全部) |
| DELETE | 删除数据 |
| PATCH | 修改数据(部分) |
① 什么时候会使用到 提交数据 这种场景呢?
- 想在手机和电脑上浏览同一份订单数据,那这份订单数据应该保存在服务器上。
- 注册了一个百度账号,手机端和电脑端也想要去登录该账号,账号信息也该保存在服务器上
总结:数据提交的场景 —— 当数据需要在服务器上保存的时候
② 如何将数据提交到 服务器上呢?
axios请求配置: (在原来仅有的URL属性之外加上了 method 和 data 两个配置项)
url : 请求的URL网址method:请求的方法,GET 可省略不写(不区分大小写)
data:提交数据(data:{ 参数名:参数值 })
(如果是要请求数据,那么就是params:{ 参数名:参数值 })
③ 案例-数据提交 - 注册账号
需求:通过 axios 提交用户名和密码,完成注册功能
注册用户URL地址:http://hmajax.itheima.net/api/register
请求方法:POST
参数名:
username 用户名(中英文和数字组成,最少8位)
password 密码(最少6位)
④点击注册用户之后,控制台就会返回注册结果,显示已经注册成功了。
注意:不能跟视频中注册的用户名一样,否则报错,自己换一个用户名就行
由此衍生出一计:运用已经注册过的用户名再注册一次,如果报错,那么就说明已经注册成功了。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>请求方法-数据提交</title>
</head>
<body><button class="btn">注册用户</button><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>/*注册用户:http://hmajax.itheima.net/api/register请求方法:POST参数名:username:用户名(中英文组成,最少8位)password:密码(最少6位)目标:点击按钮,通过axios提交用户和密码,完成注册*/document.querySelector('.btn').addEventListener('click',() => {axios({url:"http://hmajax.itheima.net/api/register",//指定请求方法method:'post',//提交数据data:{username:'ithaima789',password:'123456'}}).then(result => {console.log(result)})})</script></body>
</html>
5.axios错误处理
场景:再次注册相同的账号,会遇到报错信息
处理:用更直观的方式,给普通用户·展示错误信息(例如弹框)
语法:在 then 方法后面,通过点语法调用catch方法,传入回调函数并定义形参



<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>axios错误处理</title>
</head>
<body><button class="btn">注册用户</button><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>/*注册用户:http://hmajax.itheima.net/api/register请求方法:POST参数名:username:用户名(中英文组成,最少8位)password:密码(最少6位)目标:点击按钮,通过axios提交用户和密码,完成注册需求:使用axios错误处理语法,拿到报错信息,弹框反馈给用户*/document.querySelector('.btn').addEventListener('click',() => {axios({url:"http://hmajax.itheima.net/api/register",//指定请求方法method:'post',//提交数据data:{username:'ithaima789',password:'123456'}}).then(result => {console.log(result)//catch方法拿到错误,还要传入一个回调函数}).catch(error => {//处理错误信息console.log(error)//把真正错误原因取出来console.log(error.response.data.message)alert(error.response.data.message)})})</script></body>
</html>

axios中,如果成功了,那么就会调用 then的回调函数执行;失败则会调用 catch 的回调函数执行
6. HTTP协议 - 请求报文
①HTTP协议:规定了浏览器发送及服务器返回内容的格式
②请求报文:浏览器按照HTTP协议要求的格式,发送给服务器的内容
③请求报文组成部分:
| 1.请求行 | 请求方法,URL,协议 |
| 2.请求头 | 以键值对的格式携带的附加信息,比如Content-Type |
| 3.空行 | 分隔请求头,空行之后的是发送给服务器的资源 |
| 4.请求体 | 发送的资源 |
查看请求报文 :网络 --> Fetch / XHR --> 标头 / 负载
请求行、请求头:在标头中的请求标头可以看(而之所以不是 json 格式是因为浏览器将之格式化了,点击旁边原始则能看到 json 格式)


请求体(发送的资源)可以在 “负载” 中查看,同样点击 “原始”就能看到原始 json 请求体,也就是 data 中发送的数据

7.请求报文 - 错误排查
需求:通过请求报文排查错误原因,并修复
现情况:输入正确用户名和密码无法登录
- 用户名: itheima007
- 密码:7654321
- 在网页中输入用户名和密码发现登陆出错,不能登录
- 打开开发者工具,将源码中 input 输入框中 密码框类型 type 设置为 text 可见,确保密码没有输入错误
- 返回代码中 axios 里边携带的 用户名和密码 没有 出错,接着一步步往上定位到 用户名和密码的 定义,最终是发现了 密码定义 时获取的是用户名输入框 的内容。最终排除错误。


8.响应报文
HTTP协议:规定了浏览器发送及服务器返回内容的格式
响应报文:服务器按照HTTP协议要求的格式,返回给浏览器的内容
| 1.响应行(状态行) | 协议、HTTP响应状态码、状态信息 |
| 2.响应头 | 以键值对的格式携带的附加信息,比如Content-Type |
| 3.空行 | 分隔响应头,空行之后是服务器返回的资源 |
| 4.响应体 | 返回的资源 |
①HTTP响应状态码:用来表明请求是否成功完成
404 :服务器找不到资源
| 状态码 | 说明 |
| 1xx | 信息 |
| 2xx | 成功 |
| 3xx | 重定向消息 |
| 4xx | 客户端错误 |
| 5xx | 服务端错误 |
②查看响应报文(在“响应标头”当中或“响应” 中)
- 当 故意把 URL 写错,然后就 能得到 404 状态码(服务器找不到资源),以及Not Found 状态信息:未找到。
- 如果是输入的 用户名 或密码错误,那么响应标头返回的状态信息就会 是 request
- 如果成功的话,那么返回状态信息 OK
补充:“响应” 中的信息有 :- code:后端定义的业务状态码。
10006:密码错误
10001:用户找不到
10004:用户没登陆或token过期
99999:后端自定义的系统异常
0 / 200:请求成功- message:表示请求的处理结果(直接中文表示,例”用户名或密码输入错误“)
- data:请求中,发送的数据,后端返回的核心数据部分

“响应”中查看返回的 资源体

9.接口文档
定义:描述接口的文章(后端工程师)
接口:使用AJAX和服务器通讯时 ,使用URL,请求方法,以及参数
例如该接口(重点详介绍查询参数):
- 参数名 pname ,位置是 query ,意思是查询,那么我就能知道它是查询参数,所以就知道了在 axios 发送请求时 ,pname要写在 params 配置项中
- 如果请求参数是 body 参数,那么就是请求体参数,在 axios 发送时,要写在 data 配置项中
AJAX该部分的接口文档:欢迎使用 - B站-AJAX和黑马头条-数据管理平台


①编写登录页代码:
- 一个登录按钮,一个用户名、密码输入框(input中id属性值和label中for属性值一样,当),当点击label标签中的文字时,浏览器会自动把光标聚焦到输入框中
- 获取用户名输入框、密码输入框中的 value 值赋值给变量,给按钮添加点击事件,点击即发送请求,请求时将 参数传入
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>接口文档</title>
</head>
<body><button class="btn">登录</button><br><label for="us">用户名</label><input type="text" value="小明" id="us" class="username" placeholder="输入用户名" name="username" required><br><label for="pa">密码</label><input type="password" value="1234567" id="pa" class="password" placeholder="输入密码" name="password" disabled><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>//用户注册const username = document.querySelector('.username').valueconst password = document.querySelector('.password').valuedocument.querySelector('.btn').addEventListener('click',() => {axios({url:"http://hmajax.itheima.net/api/login",method:"post",data:{username:'itheima007',password:'7654321'}}).then(result => {alert('注册成功')}).catch(reason => {alert('注册失败')})})</script></body>
</html>

② 案例 - 用户登录
- 点击登录时,判断用户名和密码长度
- 提交数据和服务器通信
- 提示信息(成功是绿色提示框,失败是红色提示框)
注意:在成功时需要提示框,失败时需要提示框,密码和用户名长度不符合规范时需要提示框,都是一样的逻辑,所以直接将之封装为函数
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>案例_登录</title><!-- 引入bootstrap.css --><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css"><!-- 公共 --><style>html,body {background-color: #EDF0F5;width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;}.container {width: 520px;height: 540px;background-color: #fff;padding: 60px;box-sizing: border-box;}.container h3 {font-weight: 900;}</style><!-- 表单容器和内容 --><style>.form_wrap {color: #8B929D !important;}.form-text {color: #8B929D !important;}</style><!-- 提示框样式 --><style>.alert {transition: .5s;opacity: 0;}.alert.show {opacity: 1;}</style>
</head><body><div class="container"><h3>欢迎-登录</h3><!-- 登录结果-提示框 --><div class="alert alert-success" role="alert">提示消息</div><!-- 表单 --><div class="form_wrap"><form><div class="mb-3"><label for="username" class="form-label">账号名</label><input type="text" class="form-control username"></div><div class="mb-3"><label for="password" class="form-label">密码</label><input type="password" class="form-control password"></div><button type="button" class="btn btn-primary btn-login"> 登 录 </button></form></div></div><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>// 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信// 目标2.使用提示框,反馈提示信息// 2.1 获取提示框const myAlert = document.querySelector('.alert')//2.2 封装提示函数,重复调用,满足提示需求// 功能 :// 1.显示提示框// 2.不同提示文字msg,成功绿色,失败红色isSuccess(true成功,false失败)// 3.过2 秒后,让提示框自动消失function alertFn(msg,isSuccess) {//1.显示提示框 myAlert.classList.add('show')//2.实现细节(给提示框中放入消息)myAlert.innerText = msg//给框设置背景色,如果外边传进来是 true ,那么就给出一个成功类名,否则是失败类名const bgStyle = isSuccess ? 'alert-success':'alert-danger'//确认类名之后将其添加到提示框中myAlert.classList.add(bgStyle)//3. 过2秒隐藏setTimeout(() => {myAlert.classList.remove('show')//提示:避免类名冲突,重置背景色,也就是文字和背景色要一同消失myAlert.classList.remove(bgStyle)},2000)}// 1.1 登录-点击事件document.querySelector('.btn-login').addEventListener('click', () => {// 1.2 获取用户名和密码const username = document.querySelector('.username').valueconst password = document.querySelector('.password').value// console.log(username, password)// 1.3 判断长度if (username.length < 8) {alertFn('用户名必须大于8位',false)return // 阻止代码继续执行}if (password.length < 6) {alertFn('密码必须大于等于6位',false)return // 阻止代码继续执行}// 1.4 基于axios提交用户名和密码// console.log('提交数据到服务器')axios({url: 'http://hmajax.itheima.net/api/login',method: 'POST',data: {username,password}}).then(result => {console.log(result)//想在表面展现后端给出的message提示信息,直接右键复制路径alertFn(result.data.message,true)}).catch(error => {console.log(error)alertFn(error.data.message,false)})})</script>
</body></html>
逐个拆解需求:
点击登录时,判断用户名和密码长度:
为按钮注册点击事件,点击之后获取输入框中输入的用户名和密码,简单进行用户名和密码的长度判断(长度不符合,用 return 组织代码继续进行)
其实这里仅仅是对输入内容进行前端简单校验,还未涉及到与后端交互是否与注册的用户名和密码一致
提交数据和服务器通信
axios发送请求,经典 url,method,data,并且用于捕获成功的 then 方法,以及捕获失败的 catch 方法

提示信息
在判断用户名长度、密码长度、登陆成功、登陆失败,这四种情况都必须使用提示框进行提示,因为情况都一样,所以选择封装函数进行重复调用。
- 首先获取提示框,在html中提示框仅用 div来进行简单表示
- 接着将传入的信息覆盖原信息.如果是判断长度部分,那么调用函数时,传入的形参msg就是我们 aler 出来的 “密码不能小于8位”这样的字符串;如果是关于登录成功与否的信息,那么就需要从then或catch中捕获的对象中找(简而言之,就是判断长度的msg仍然是自己写出的对象,而是否登陆成功的msg是要到控制台的对象.data.message中)
注意:class类中,当有多个类型时,后边的类值会把前边的类值覆盖掉,所以这里才会有最后要把背景色给移除

直接浏览器中搜索 Alert 能知 该提示框表示成功和失败时的代码如何


10.form-serialize 插件
作用:快速收集表单元素的值(现在好像不用这个了,用FornData API)
语法:
- 首先进行引入
- 然后使用 serialize 函数,其中第一个参数是获取的哪一个表单元素的表单的值,第二个参数是一个配置对象(实际开发中只需要 hash 和 empty 即可)
- 引入 该插件,插件文件在 lib 文件夹中
- 获取表单将之作为 serialize 的第一个参数,第二个参数是个配置对象,其中 hash 为true就会获取到的是 json 对象,否则是查询字符串 ,例如 ** = xx; empty为 true 表示输入框为空时,在获取的时候也要把 空值获取出来。
简言 ,serialize函数用来获取输入框中输入的内容,并且输入框 input 中的 name的值会作为 控制台获取时 的 key,而输入的内容就作为 value(name值作为对象属性名)

hash和empty都 为 true

hash改为false,而empty不变
可见获取到的值已经是查询字符串形式了

hash为true,而empty为 false
可见如果输入为空那么就不会获取空值

①使用 form-serialize 插件,收集用户名和密码,完善登录案例
- 获取 form 元素作为 serialize 函数的第一个参数
- 解构将旧的变量名的值赋值给新的变量名,虽然关乎旧的变量值,但是只出现了新旧变量名。


