什么是 AJAX ?
AJAX 是异步的 JavaScript 和 XML(Asynchronous JavaScript And XML)。
简单理解AJAX:是一种客户端与服务器进行网络通信技术,AJAX通常使用XMLHttpRequest 对象来发送请求和接收响应
现代开发中我们通常使用 JSON格式来进行数据的传输
为何学 AJAX?
- 以前我们的数据都是写在代码里固定的, 无法随时变化
- 现在我们的数据可以从服务器上进行获取,让数据变活
什么是Axios
Axios 是一个别人封装好的网络请求库,可以方便的让我们完成与服务器进行网络通讯。
浏览器端Axios是基于AJAJX对象XMLHttpRequest 来进行封装的
前端开发和鸿蒙开发都需要到Axios
什么是服务器?
在网络上提供服务器的一台电脑,比如提供数据服务
Axios基本用法
咱们来看看 Axios如何使用
axios官网
// 1. 引入 axios.js 文件到自己的网页中
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
// 2. 使用axios
axios({
url: '目标资源地址'
}).then((res) => {
// res是一个对象,保存了服务器返回的数据
// ✨✨✔️其中:res.data 是保存了服务器的响应数据,我们经常使用它
})
试一试:使用axios请求 https://api-vue-base.itheima.net/api/joke
获取一条随机笑话
实现效果:
点击【按钮】获取一条【随机的笑话】并【展示到页面】上
<!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>AJAX概念和axios使用</title>
</head>
<body>
<!--
axios库地址:https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
省份数据地址:http://hmajax.itheima.net/api/province
目标: 使用axios库, 获取省份列表数据, 展示到页面上
1. 引入axios库
-->
<p class="my-p"></p>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
<script>
// 2. 使用axios函数
axios({
// url: 'http://hmajax.itheima.net/api/province'
url:'https://api-vue-base.itheima.net/api/joke'
}).then(result => {
console.log(result)
// 好习惯:多打印,确认属性名
console.log(result.data)
// console.log(result.data.list.join('<br>'))
// 把准备好省份列表,插入到页面
document.querySelector('.my-p').innerHTML = result.data
})
</script>
</body>
</html>
1. 认识URL
刚刚请求的地址url并不是随意的一些字符串,他叫做 URL,也可以叫做统一资源定位符
URL:统一资源定位符(Uniform Resource Locator),简称网址,用于定位网络中的资源
- 每个有效的 URL 都指向一个唯一的资源:网页,图片,数据,视频,音频等等
- URL 的组成?
-
- 协议,域名,资源路径(URL 组成有很多部分,我们先掌握这3个重要的部分即可)
- 什么是 http 协议 ?
-
- 叫超文本传输协议,规定了浏览器和服务器传递数据的格式(而格式具体有哪些今天我们就会学到)
- 什么是域名 ?
-
- 标记服务器在互联网当中的方位,网络中有很多服务器,你想访问哪一台,就需要知道它的域名才可以
- 什么是资源路径 ?
-
- 一个服务器内有多个资源,资源路径用于标识你要访问的资源具体的位置
2. JSON
2.1. 基本概念
什么是JSON?
JSON 是一种按照 JavaScript 对象语法的数据格式,虽然它是基于 JavaScript 语法,但它独立于 JavaScript,许多【程序环境】能够读取(解读)和生成 JSON。
JSON的作用?
JSON是一个字符串,常用于存储和传递数据
语法规则:
- 是一个字符串(配置文件中两边可以不写引号)
- 属性名用双引号包裹,
- 属性值如果是字符串也必须用双引号包裹
- 对象{},数组[]
const jsonObj='{"name":"jack","age":18}'
const arr = '["你好","西兰花炒蛋"]'
const arrObj = '[{"name":"jack"},{"name":"rose"}]'
Axios默认在它的底层已经通过 JSON.parse()将服务器传过来的json字符串变成了js数据类型
2.2. JSON字符串转换
如果要在 JSON 和对象之间转换,就需要用到对应api 啦:(数组也是对象)
JSON.stringify(对象)// 转为 JSON
JSON.parse(JSON)
// JSON.parse
const jsonObj='{"name":"jack","age":18}'
const obj = JSON.parse(jsonObj)
const jsonArr = '["你好","西兰花炒蛋"]'
const arr= JSON.parse(jsonArr)
// JSON.stringify
const p={
name:'rose',
age:20
}
let jsonStr = JSON.stringify(p)
3. 案例-新闻
结合刚刚测试的获取新闻数据的 URL 地址,咱们来做一个案例:
需求:
- 打开页面时,使用axios 请求URL https://hmajax.itheima.net/api/news 获取新闻并渲染到页面上
3.2. 完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.box {
padding: 5px;
}
.item {
display: flex;
padding: 10px;
box-shadow: 1px 1px rgba(0,0,0,0.1);
margin: 5px 0px;
}
.item img {
width: 104px;
height: 78px;
border-radius: 5px;
}
.item h3 {
font-size: 16px;
font-weight: 500;
height: 40px;
line-height: 20px;
overflow: hidden;
}
.left div span {
font-size: 12px;
}
.left div {
margin-top: 10px;
}
</style>
</head>
<body>
<div class="box">
<!-- <div class="item">
<div class="left">
<h3>一抓一放、张手就来:华为Mate 70/X6
系列手机、MatePad Pro 13.2 英寸平板 2..</h3>
<div>
<span>新京报 2024-12-7 09:17:02</span>
<span>94评</span>
</div>
</div>
<img src="https://img.ithome.com/newsuploadfiles/thumbnail/2024/11/812592_240.jpg" alt="">
</div> -->
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
<script>
axios({
url:'https://hmajax.itheima.net/api/news'
}).then(result => {
console.log(result)
// 好习惯:多打印,确认属性名
console.log(result.data.data)
let str = ``
result.data.data.forEach(item=>{
str+=`
<div class="item">
<div class="left">
<h3>${item.title}</h3>
<div>
<span>${item.source} ${item.time}</span>
<span>${item.cmtcount}评</span>
</div>
</div>
<img src="${item.img}" alt="">
</div>
`
})
// 把准备好省份列表,插入到页面
document.querySelector('.box').innerHTML = str
})
</script>
</body>
</html>
4. URL 查询参数
目前咱们只能获取固定的数据,如果要查询特定的数据怎么办呢?可以通过 URL 查询参数来实现
4.1. 什么是URL查询参数
URL查询参数是提供给网络服务器的额外参数。这些参数是用 & 符号分隔的键/值对列表。在返回资源之前,Web 服务器可以使用这些参数来执行额外的操作。每个 Web 服务器都有自己关于参数的规则,唯一可靠的方式来知道特定 Web 服务器是否处理参数是通过询问 Web 服务器所有者
简而言之: 携带给服务器额外信息,让服务器返回我想要的某一部分数据而不是全部数据
咱么先通过 2 个预先准备好的地址来确认一下
拼接在 URL 末尾的就是查询参数:
? 隔开之后使用&分隔的键值对列表
4.2. 如何确认 URL 查询参数
实际开发时,服务器的所有者会提供 URL 查询参数的信息,比如
地址:http://hmajax.itheima.net/api/city
说明获取某个省所有的城市查询
参数名:pname
说明: 传递省份或直辖市名,比如 北京、广东省…
4.3. axios 如何携带查询参数?
- 使用 params 选项即可
axios({
url: 'http://测试服务器/资源路径',
params: {
key: 'value',
key2: 'value2'
}
}).then(res => {
// 接受并使用数据
})
4.4. 城市查询案例(讲解)
url地址:http://hmajax.itheima.net/api/city
说明获取某个省所有的城市查询
参数名:pname
说明: 传递省份或直辖市名,比如 北京、广东省…
<!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>AJAX概念和axios使用</title>
</head>
<body>
<input type="text" class="pname" placeholder="输入如:广东省"> <button class="query">查询城市</button>
<p class="my-p"></p>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
<script>
document.querySelector('.query').addEventListener('click', function () {
let pname = document.querySelector('.pname').value
// 2. 使用axios函数
axios({
// url: 'http://hmajax.itheima.net/api/city?pname='+pname,
url: 'http://hmajax.itheima.net/api/city',
params:{
pname:pname
}
}).then(result => {
console.log(result)
// 好习惯:多打印,确认属性名
console.log(result.data)
// console.log(result.data.list.join('<br>'))
// 把准备好省份列表,插入到页面
document.querySelector('.my-p').innerHTML = result.data.list.join('<br>')
})
})
</script>
</body>
</html>
4.5. 案例-查询-地区列表(自己写)
需求:根据输入的省份名字和城市名字,查询下属地区列表
查询地区: http://hmajax.itheima.net/api/area
参数名:
pname:省份名字
cname:城市名字
<!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>AJAX概念和axios使用</title>
</head>
<body>
<input type="text" class="pname" placeholder="输入如:广东省">
<input type="text" class="cname" placeholder="输入如:深圳市">
<button class="query">查询地区</button>
<p class="my-p"></p>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
<script>
document.querySelector('.query').addEventListener('click', function () {
let pname = document.querySelector('.pname').value
let cname = document.querySelector('.cname').value
// 2. 使用axios函数
axios({
url: 'http://hmajax.itheima.net/api/area',
params:{
pname:pname,
cname:cname
}
}).then(result => {
console.log(result)
// 好习惯:多打印,确认属性名
console.log(result.data)
// console.log(result.data.list.join('<br>'))
// 把准备好省份列表,插入到页面
document.querySelector('.my-p').innerHTML = result.data.list.join('<br>')
})
})
</script>
</body>
</html>
5. 请求方法和数据提交
到目前为止都是向服务器获取数据,接下来咱们来看看如何向服务器发送数据
- GET请求方法是axios的默认请求方法
- 向服务器发送数据我们常用的方式是POST请求方法(需要显示指定)
提交数据给服务器的场景:用户登录,注册,修改密码等
5.1. Axios POST请求方法
// ✨✨需要设置method 和 data 这2个新的选项
axios({
url:'请求URL',
method:'post',
data:{
key:'value',
key1:'value1',
.....
},
})
5.2. POST请求举例
使用axios的post请求实现用户注册
测试用 url
请求地址(url):http://hmajax.itheima.net/api/register
注册用户
请求方法:POST
参数:username,password
说明:username 用户名(中英文和数字组成, 最少8位),password 密码(最少6位)
<!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>
</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: 'itheima521',
password: '12345678'
}
})
.then(res=>{
console.log(res.data);
})
})
</script>
</body>
</html>
5.3. axios 错误处理
- 如果注册相同的用户名,则会遇到注册失败的请求,也就是 axios 请求响应失败了,你会在控制台看到如图的错误:
- 在 axios 语法中要如何处理呢?
-
- 因为,普通用户不会去控制台里看错误信息,我们要编写代码拿到错误并展示给用户在页面上
- 使用 axios 的 catch 方法,捕获这次请求响应的错误并做后续处理,语法如下:
axios({
// 请求选项
}).then(res => {
// 处理数据
}).catch(err => {
// 处理错误
})
- 对应代码
document.querySelector('.btn').addEventListener('click', function () {
// console.log('点了')
// 通过axios提交用户数据,完成用户注册
axios({
url: 'http://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'itheima521',
password: '123456'
}
}).then(res => {
console.log(res.data)
}).catch(err => {
// 重复注册,通过弹框提示用户
// console.log(err)
// console.log(err.response.data)
alert(err.response.data.message)
})
})
6. 接口文档
到目前为止,咱们请求的 URL 地址,请求的方法都是直接提供好了,日常开发中如何获取这些信息呢?
日常开发中一般通过【接口文档】来获取这部分信息,【接口文档】一般由后端工程师编写
咱们通过接口文档和服务器通讯这个操作,也可以叫做 【调接口】
6.1. 接口文档实践(登录)
咱们结合 登录-form 接口来完成用户登录,关注红色部分
<!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:点击登录时,用户名和密码长度判断,并提交数据和服务器通信
// 1.1 登录-点击事件
document.querySelector('.btn-login').addEventListener('click', () => {
// 1.2 获取用户名和密码
const username = document.querySelector('.username').value
const password = document.querySelector('.password').value
// console.log(username, password)
// 1.3 判断长度
if (username.length < 8) {
console.log('用户名必须大于等于8位')
return // 阻止代码继续执行
}
if (password.length < 6) {
console.log('密码必须大于等于6位')
return // 阻止代码继续执行
}
// 1.4 基于axios提交用户名和密码
// console.log('提交数据到服务器')
axios({
url: 'http://hmajax.itheima.net/api/login',
method: 'POST',
data: {
username,
password
}
}).then(result => {
console.log(result)
console.log(result.data.message)
}).catch(error => {
console.log(error)
console.log(error.response.data.message)
})
})
</script>
</body>
</html>
7. HTTP协议
HTTP协议规定了【客户端发送的内容】及【服务器返回内容】的【格式】
咱们使用axios和服务器通讯的时候,本质上是发送和接收了符合 HTTP 协议规定的内容,接下来咱们来看看内容长啥样
7.1. 请求报文
请求报文:浏览器按照HTTP协议要求的格式,发送给服务器的内容
请求报文的组成部分:
- 请求行:请求方法,URL,协议(第一行)
- 请求头:以键值对的格式携带的附加信息,比如:Content-Type(第二行开始到空行)
- 空行:分隔请求头,空行之后的是发送给服务器的资源(空行)
- 请求体:发送的资源(空行之后)
学会请求报文的查看,可以帮助我们来进行排错
7.2. 响应报文
响应报文:服务器按照HTTP协议要求的格式,返回给浏览器的内容
响应报文组成:
- 响应行(状态行):协议、HTTP响应状态码、状态信息(第一行)
- 响应头:以键值对的格式携带的附加信息,比如:Content-Type(第一行到空行)
- 空行:分隔响应头,空行之后的是服务器返回的资源(空行)
- 响应体:返回的资源(空行之后)
咱们一般需要关注,响应行,响应体即可
不同于请求报文,响应报文是由服务器返回的,咱们无法修改,根据响应报文提供的信息,做出处理即可
响应行中可以获取到状态码,用来表示请求是否成功完成。
8. form-serialize 插件
- 我们前面收集表单元素的值,是一个个标签获取的
- 如果一套表单里有很多很多表单元素,如何一次性快速收集出来呢?
- 使用 form-serialize 插件提供的 serialize 函数就可以办到
- form-serialize 插件语法:
-
- 引入 form-serialize 插件到自己网页中
- 📎form-serialize.js 下载到项目lib文件夹中
<script src="./lib/form-serialize.js"></script>
-
- 使用 serialize 函数
<form action="javascript:;" class="example-form">
<input type="text" name="username">
<br>
<input type="text" name="password">
<br>
<input type="button" class="btn" value="提交">
</form>
/**
* 2. 使用serialize函数,快速收集表单元素的值
* 参数1:要获取哪个表单的数据
* 表单元素设置name属性,值会作为对象的属性名
* 建议name属性的值,最好和接口文档参数名一致
* 参数2:配置对象
* hash 设置获取数据结构
* - true:JS对象(推荐)一般请求体里提交给服务器
* - false: 查询字符串
* empty 设置是否获取空值
* - true: 获取空值(推荐)数据结构和标签结构一致
* - false:不获取空值
*/
const form = document.querySelector('.example-form')
const data = serialize(form, { hash: true, empty: true })
8.1. 使用serialize插件重写登录页面
9. 综合案例练习
- 页面进入的时候从服务器获取评论数据显示:接口文档
<!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>
<style>
.wrapper {
width: 800px;
display: flex;
justify-content: flex-end;
}
.wrapper textarea {
height: 50px;
flex: 1;
padding: 10px;
border-radius: 4px;
border-color: #e4e4e4;
background: #fff;
outline: none;
resize: none;
}
.wrapper button {
width: 70px;
margin-left: 10px;
border: none;
color: #fff;
background: #00aeec;
border-radius: 4px;
cursor: pointer;
}
.wrapper .total {
margin-right: 80px;
margin-top: 5px;
color: #999;
}
.list {
width: 800px;
border: 1px solid #efce9c;
background-color: rgb(231, 238, 191);
padding: 10px;
}
.list p {
font-size: 12px;
}
.msg {
height: 20px;
background-color: rgb(187, 249, 248);
}
</style>
</head>
<body>
<div class="wrapper">
<textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea>
<button>发布</button>
</div>
<div class="wrapper">
<span class="total">0/200字</span>
</div>
<div class="list">
<p>评论信息:</p>
<p class="msg">善语结善缘~~请发表你的评论</p>
</div>
<script src="./lib/axios.js"></script>
<script>
// 1. 获取评论方法
function getList() {
axios({
url: 'https://hmajax.itheima.net/api/cmtlist',
params: {
page: 1
}
})
.then(res => {
let dataList = res.data.data
let str = ''
dataList.forEach(item => {
str += ` <p data-id="${item.id}" class="msg">${item.content}</p>`
})
document.querySelector('.list').innerHTML = str
})
.catch(err=>{
alert(err.response.data.message)
})
}
// 2. 初始化新增数据
function initpublishData() {
const textBox = document.querySelector('#tx')
textBox.addEventListener('keyup', function (e) {
if (e.key === 'Enter') {
axios({
url:'https://hmajax.itheima.net/api/addcmt',
method:'POST',
data:{
username:'ivan',
content:textBox.value
}
}).then(res=>{
textBox.value = ''
// 当发表一条新评论,则重新问服务器要最新数据回来显示在页面上
getList()
})
.catch(err=>{
alert(err.response.data.message)
})
}
})
}
// 3. 删除指定数据
function initDelData(){
document.querySelector('.list').addEventListener('click',function(e){
if(e.target.tagName === 'P'){
let id = e.target.dataset.id
axios({
url:'https://hmajax.itheima.net/api/delcmt',
params:{
id:id
}
})
.then(res=>{
// 删除成功后,问服务器要删除以后的数据
getList()
})
.catch(err=>{
alert(err.response.data.message)
})
}
})
}
// 调用方法
getList()
initpublishData()
initDelData()
</script>
</body>
</html>