Ajax 笔记持续更新中
一、服务器相关的基础概念
1. 客户端
2. 服务器
3. 客户端与服务器通信的过程
4. 资源与 URL 地址
5. URL 地址
6. 什么是 Ajax
二、Ajax 的基础用法
1. 使用 Ajax 请求数据的 5 种方式
像这样修改个人信息,就是使用 PUT
2. axios
我们不是一上来就写 Ajax 的原生代码,因为 Ajax 的原生代码会非常复杂。
ajax 技术分原生和插件,先学习插件会轻松些。原生会放到后面讲解。
中文官网地址:http://www.axios-js.com/
英文官网地址:https://www.npmjs.com/package/axios
注意:学习 Ajax 我们需要用到浏览器的一个新面板
Network
3. 基于 axios 发起 GET 请求
测试:
4. GET 请求的查询参数
测试:
5. 在 GET 请求中携带多个查询参数
6. URL 编码
GET 案例:新闻列表
完成这个案例需要先复习一下 对象的解构赋值
<script>
// 解构赋值:目的: 快速的取值
const obj = {
username: 'zs',
age: 18,
car: {
name: '劳斯莱斯',
price: 1000
},
house: {
name: '新疆海景房',
price: 500000
}
}
// ========================= 取出对象obj的car和house属性 =========================
// let car = obj.car
// let house = obj.house
// console.log(car)
// console.log(car.name)
// console.log(car.price)
// console.log(house)
// console.log(house.name)
// console.log(house.price)
// ========================= 解构赋值写法 =========================
// let {car, house} = obj
// console.log(car, house)
// ========================= 重命名 =========================
// let {car: car2} = obj
// console.log(car2)
// ========================= 深层解构 =========================
// let {car: {name, price}} = obj
// console.log(name, price)
// let {house: {name, price}} = obj
// console.log(name, price)
// 对 car 和 house 都深层解构
// name: houseName 将 house 的 name 值赋给 houseName
// let {car: {name, price}, house:{name: houseName,price: housePrice}} =obj
// console.log(name, price, houseName, housePrice)
// ========================= 解构赋值还可以用于在函数参数上 =========================
// function fn(info) {
// console.log(info)
// let {car, house} = info
// console.log(car, house)
// }
// fn(obj)
// 改良fn函数写法 (直接在形参位置解构)
function fn({car: {name, price}, house}) {
console.log(name, price, house)
}
fn(obj)
function fn2([x, y, z]) {
console.log(x, y, z)
}
fn2([10, 20, 30])
</script>
实现:
(解构思想)
(实现解构)
案例思想:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<!-- 导入样式表 -->
<link rel="stylesheet" href="./assets/news.css" />
</head>
<body>
<!-- 新闻列表 -->
<div id="news-list">
<!-- 新闻的 item 项 -->
<div class="news-item">
<img class="thumb" src="http://www.liulongbin.top:3009/images/5.webp" alt="" />
<div class="right-box">
<!-- 新闻标题 -->
<h1 class="title">5G商用在即,三大运营商营收持续下降</h1>
<div class="footer">
<div>
<!-- 新闻来源 -->
<span>胡润百富</span>
<!-- 发布日期 -->
<span>2019-10-28 10:14:38</span>
</div>
<!-- 评论数量 -->
<span>评论数:66</span>
</div>
</div>
</div>
</div>
<!-- 导入axios -->
<script src="./lib/axios.js"></script>
<script>
// 获取新闻列表对象
const list = document.querySelector('#news-list')
// 步骤:
// 1. 获取数据 ==> 通过 axios 发送GET请求
// 请求地址: http://www.liulongbin.top:3009/api/news
// 解构
axios({
url: 'http://www.liulongbin.top:3009/api/news',
method: 'GET'
}).then(({data: res}) => {
// {data: res} 解构出来的 data, 并且重命名为 res(这对应的就是服务器响应回来的数据)
console.log(res)
console.log(res.code) // 200
console.log(res.msg) // 获取新闻列表成功
console.log(res.data) // 9 条数据
if(res.code === 200) {
// 获取成功 => 遍历 res.data 数组,将其展现到页面中
// 准备 htmlStr 来拼接html字符串
let htmlStr = ``
// item 指的就是 data 用 data 里的属性值替换原文本位置
res.data.forEach(item => {
htmlStr += `
<div class="news-item">
<img class="thumb" src="http://www.liulongbin.top:3009${item.img}" alt="" />
<div class="right-box">
<!-- 新闻标题 -->
<h1 class="title">${item.title}</h1>
<div class="footer">
<div>
<!-- 新闻来源 -->
<span>${item.source}</span>
<!-- 发布日期 -->
<span>${item.time}</span>
</div>
<!-- 评论数量 -->
<span>评论数:${item.cmtcount}</span>
</div>
</div>
</div>
`
})
// console.log(htmlStr)
// 把拼接好的 htmlStr 赋值作为 list 的内容
list.innerHTML = htmlStr
} else {
// 获取失败
alert(res.msg)
}
})
</script>
</body>
</html>
学完 map 方法之后,我们可以对新闻案例进行更加简便的改写。
解构的一些注意点:
7. result 是 axios 套壳的结果
axios 把数据套在对象 data 里面了
8. 数组 map 方法的使用
:
我们想实现把这四个 li 放进ul 里面,如何实现?
方案1:forEach 遍历然后 += 更新 htmlStr
方案2:使用 join 方法拼接字符串
方案2可以更加简单:
效果:
9. 基于 axios 发起 POST 请求
POST 案例: 用户注册
实现:
<!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>Document</title>
<link rel="stylesheet" href="./css/bootstrap-v4.6.0.css">
<link rel="stylesheet" href="./css/login.css">
</head>
<body>
<div class="login-box">
<div class="form-group">
<label for="username">Account</label>
<!-- 账号 -->
<input type="text" class="form-control" id="username" autocomplete="off">
<small id="emailHelp" class="form-text text-muted">The available account is <strong>admin</strong></small>
</div>
<div class="form-group">
<!-- 密码 -->
<label for="password">Password</label>
<input type="password" class="form-control" id="password">
<small id="emailHelp" class="form-text text-muted">The available password is <strong>123456</strong></small>
</div>
<button type="submit" class="btn btn-primary" id="btnLogin">Submit</button>
</div>
<script src="./lib/axios.js"></script>
<script>
// 请求方式 POST
// 地址 http://www.liulongbin.top:3009/api/login
// 参数: username 用户名 password 密码
// 设置一个函数来获取对象
function ts(str){
return document.querySelector(str)
}
// 点击提交按钮发送 post 请求
ts('#btnLogin').addEventListener('click', function(){
const username = ts('#username').value
const password = ts('#password').value
axios({
method: 'POST',
url: 'http://www.liulongbin.top:3009/api/login',
data: {
username,
password
}
}).then( ({data: res}) => {
if(res.code === 200) {
alert('注册成功!')
// 注册成功后跳转页面
location.href = 'https://blog.youkuaiyun.com/JOUKELOVE?type=blog'
} else {
alert(res.msg)
}
}
)
})
</script>
</body>
</html>
三、请求报文&响应报文
1. 什么是请求报文和响应报文
一旦 Ajax 请求出错了,我们需要排查问题就是在报文里排查。
2. 请求报文 - 格式
如何查看请求报文?
请求行 和 请求头部:
请求体:
3. 响应报文 - 格式
响应报文:
4. http 响应状态码
了解一些常见的响应状态码即可
5. 区分 响应状态码 和 业务状态码
一定要把他们两个区分开,不然使用 ajax 会有点懵
四、接口相关的基础概念
1. 接口的概念
2. 接口文档的概念
3. 接口测试工具 Postman
官方下载地址 : https://www.postman.com/downloads/
4. postcode 插件
我们的 VScode 里有一个插件 postcode
,效果跟 postman 是一样的。
查询图书:
添加图书:
有关 postcode,有一些需要注意的细节:
五、案例–聊天机器人
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="css/reset.css" />
<link rel="stylesheet" href="css/main.css" />
<title>聊天机器人</title>
</head>
<body>
<div class="wrap">
<!-- 头部 Header 区域 -->
<div class="header">
<h3>小思同学</h3>
<img src="img/person01.png" alt="icon" />
</div>
<!-- 中间 聊天内容区域 -->
<div class="main">
<ul class="talk_list" style="top: 0px;" id="talk_list">
<!-- 机器人 -->
<li class="left_word">
<img src="img/person01.png" /> <span>嗨,最近想我没有?</span>
</li>
<!-- 我 -->
<!-- <li class="right_word">
<img src="img/person02.png" /> <span>嗨,最近想我没有?</span>
</li> -->
</ul>
</div>
<!-- 底部 消息编辑区域 -->
<div class="footer">
<img src="img/person02.png" alt="icon" />
<input type="text" placeholder="说的什么吧..." class="input_txt" id="ipt" />
<input type="button" value="发 送" class="input_sub" id="btnSend" />
</div>
</div>
<!-- 导入 axios -->
<script src="../lib/axios.js"></script>
<script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
<audio src="" id="voice" autoplay style="display: none;"></audio>
<script>
let ipt = document.querySelector('#ipt')
let btnSend = document.querySelector('#btnSend')
let ul = document.querySelector('#talk_list')
let voice = document.querySelector('#voice')
btnSend.addEventListener('click', function(){
let content = ipt.value
// 2.创建li ==> document.creatElement()
let newLi = document.createElement('li')
// 3.设置内容 ==> innerHTML
newLi.className = 'right_word'
newLi.innerHTML = `
<img src="img/person02.png" /> <span>${content}</span>
`
// 4.添加到 ul 中 ==> appendChild
ul.appendChild(newLi)
// 发送完毕后清空我们的输入栏
ipt.value = ''
// 发送 ajax 请求获取机器人说的话
axios({
method: 'GET',
url: 'http://www.liulongbin.top:3006/api/robot',
params: {
spoken: content
}
}).then(({ data: res}) => {
console.log(res)
// 定义 text 就是机器人返回的话
let text = res.data.info.text
// 机器人说的话放到ul中展示
let leftLi = document.createElement('li')
// 设置内容
leftLi.className = 'left_word'
leftLi.innerHTML = `
<img src="img/person01.png" /> <span>${text}</span>
`
// 添加到 ul 中
ul.appendChild(leftLi)
// 代码位置一定要注意
// 封装好的文字转语音函数
getVoice(text)
})
})
// ajax请求,将机器人的文字转语音,放到函数中完成功能
// 传参 text(因为 text 是 then 里面的,想跨域使用得传参)
function getVoice(text) {
axios({
url: 'http://www.liulongbin.top:3006/api/synthesize',
method: 'GET',
params: {
text
}
}).then(({data: res}) => {
console.log(res)
// 将机器人的文字转语音结果(voiceUrl) 赋值给 audio 的 src 属性
voice.src = res.voiceUrl
})
}
</script>
</body>
</html>
我们发现了一些问题:
代码优化
我们对代码进行优化:
优化内容有:
- 回车发送消息后自动清空输入栏的内容: 参考博客的微博发布案例
- 消息记录同步适应: 参考博客的scroll家族
最终代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="css/reset.css" />
<link rel="stylesheet" href="css/main.css" />
<title>聊天机器人</title>
</head>
<body>
<div class="wrap">
<!-- 头部 Header 区域 -->
<div class="header">
<h3>小思同学</h3>
<img src="img/person01.png" alt="icon" />
</div>
<!-- 中间 聊天内容区域 -->
<div class="main">
<ul class="talk_list" style="top: 0px;" id="talk_list">
<!-- 机器人 -->
<li class="left_word">
<img src="img/person01.png" /> <span>嗨,最近想我没有?</span>
</li>
<!-- 我 -->
<!-- <li class="right_word">
<img src="img/person02.png" /> <span>嗨,最近想我没有?</span>
</li> -->
</ul>
</div>
<!-- 底部 消息编辑区域 -->
<div class="footer">
<img src="img/person02.png" alt="icon" />
<input type="text" placeholder="说的什么吧..." class="input_txt" id="ipt" />
<input type="button" value="发 送" class="input_sub" id="btnSend" />
</div>
</div>
<!-- 导入 axios -->
<script src="../lib/axios.js"></script>
<script type="text/javascript" src="js/jquery-1.12.4.min.js"></script>
<audio src="" id="voice" autoplay style="display: none;"></audio>
<script>
let ipt = document.querySelector('#ipt')
let btnSend = document.querySelector('#btnSend')
let ul = document.querySelector('#talk_list')
let voice = document.querySelector('#voice')
btnSend.addEventListener('click', function(){
let content = ipt.value
// 2.创建li ==> document.creatElement()
let newLi = document.createElement('li')
// 3.设置内容 ==> innerHTML
newLi.className = 'right_word'
newLi.innerHTML = `
<img src="img/person02.png" /> <span>${content}</span>
`
// 4.添加到 ul 中 ==> appendChild
ul.appendChild(newLi)
// 发送 ajax 请求获取机器人说的话
axios({
method: 'GET',
url: 'http://www.liulongbin.top:3006/api/robot',
params: {
spoken: content
}
}).then(({ data: res}) => {
console.log(res)
// 定义 text 就是机器人返回的话
let text = res.data.info.text
// 机器人说的话放到ul中展示
let leftLi = document.createElement('li')
// 设置内容
leftLi.className = 'left_word'
leftLi.innerHTML = `
<img src="img/person01.png" /> <span>${text}</span>
`
// 添加到 ul 中
ul.appendChild(leftLi)
// ul 滚动距离为 ul 的内容高度 ==> 可以实现滚动到底部去
ul.scrollTop = ul.scrollHeight
// 代码位置一定要注意
// 封装好的文字转语音函数
getVoice(text)
})
})
// ajax请求,将机器人的文字转语音,放到函数中完成功能
// 传参 text(因为 text 是 then 里面的,想跨域使用得传参)
function getVoice(text) {
axios({
url: 'http://www.liulongbin.top:3006/api/synthesize',
method: 'GET',
params: {
text
}
}).then(({data: res}) => {
console.log(res)
// 将机器人的文字转语音结果(voiceUrl) 赋值给 audio 的 src 属性
voice.src = res.voiceUrl
})
}
// 给输入框添加事件
ipt.addEventListener('keyup',function(e){
if(e.key === 'Enter') {
// 按下回车 对 btnSend 按钮做一次点击
btnSend.click()
// 发送完毕后清空我们的输入栏
ipt.value = ''
}
})
</script>
</body>
</html>
总结
axios 的固定语法一定要非常熟练。
如果怕自己忘记,可以经常去中文官网复习。
(中文官网地址:http://www.axios-js.com/)