Ajax入门以及Axios的详细使用(含Promise)

1. 概述

1.1 是什么

  • Ajax = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)

  • Ajax 不是新的编程语言,而是一种用于创建快速动态网页的技术

  • Ajax 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,使网页实现异步更新

  • 传统的网页(不使用 Ajax)如果需要更新内容,必需重载整个网页

  • Ajax 不需要任何浏览器插件,但需要用户允许 JavaScript 在浏览器上执行

  • XMLHttpRequest只是实现 Ajax 的一种方式

1.2 为什么

  • 以前数据都是写在代码里固定的, 无法随时变化

  • 现在数据可以从服务器上进行获取,让数据变活

1.3 入门程序

  • 需求:从服务器获取省份列表数据,展示到页面上

  • 步骤:

    • 引入 axios
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    
    • 基本语法
    axios({
    	url: "目标资源地址",
    }).then(result => {
    	// 对服务器返回的数据做后续处理
    });
    
  • 示例

<div id="root"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
	axios({
	url: "http://hmajax.itheima.net/api/province",
	}).then(result => {
	document.querySelector("#root").innerHTML = result.data.list.join("<br>");
	});
</script>

2. axios

2.1 URL

  • URL:统一资源定位符,简称网址,用于定位网络中的资源(网页,图片,数据,视频,音频等)

  • 组成:协议,域名,资源路径(比较重要的三部分)

  • http 协议:超文本传输协议,规定了浏览器和服务器传递数据的格式

  • 域名:标记服务器在互联网当中的方位,网络中有很多服务器,你想访问哪一台,需要知道它的域名

  • 资源路径:一个服务器内有多个资源,用于标识你要访问的资源具体的位置

  • 查询参数:携带给服务器额外信息,让服务器返回想要的某一部分数据而不是全部数据

    • 格式:http://xxxx.com/xxx/xxx?参数名1=值1&参数名2=值2

    • 参数名一般是后端规定的,值前端看情况传递即可

  • axios 如何携带查询参数?

axios({
	url: "目标资源地址",
	params: {
	参数名: 值,
	},
}).then(result => {
	// 对服务器返回的数据做后续处理
});
  • 示例 1:获取“河北省”下属的城市列表
<div id="root"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
	axios({
	url: "http://hmajax.itheima.net/api/city",
	params: {
	pname: "河北省",
	},
	}).then(result => {
	document.querySelector("#root").innerHTML = result.data.list.join("<br>");
	});
</script>
  • 示例 2:根据输入的省份名字和城市名字,查询下属地区列表

<!-- 样式 -->
<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>
<div class="container">
	<form id="editForm" class="row">
	<!-- 输入省份名字 -->
	<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 />
	<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: 城市名字
 */
	// 绑定点击事件
	document.querySelector(".sel-btn").addEventListener("click", () => {
	// 获取输入框的值
	let pName = document.querySelector(".province").value;
	let cName = document.querySelector(".city").value;
	// 利用axios获取数据
	axios({
	url: "http://hmajax.itheima.net/api/area",
	params: {
	pname: pName,
	cname: cName,
	},
	}).then(result => {
	document.querySelector(".list-group").innerHTML = result.data.list
	.map(item => `<li class="list-group-item">${item}</li>`)
	.join("");
	});
	});
</script>

2.2 数据提交

  • 常用请求方法
请求方法操作
GET获取数据(默认请求方式)
POST提交数据
PUT修改数据(全部)
DELETE删除数据
PATCH修改数据(部分)
  • axios 如何提交数据到服务器
axios({
	url: "目标资源地址",
	method: "请求方法",
	data: {
	参数名: 值,
	},
}).then(result => {
	// 对服务器返回的数据做后续处理
});
  • 示例:注册账号,提交用户名和密码到服务器保存
<button>点击注册</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
	document.querySelector("button").addEventListener("click", () => {
	axios({
	url: "http://hmajax.itheima.net/api/register",
	method: "post",
	data: {
	username: "itheima666",
	password: "12345678",
	},
	}).then(result => {
	console.log(result);
	});
	});
</script>

2.3 axios 错误处理

axios({
	// ...请求选项
})
	.then(result => {
	// 处理成功数据
	})
	.catch(error => {
	// 处理失败错误
	});
  • 示例:
<button>点击注册</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
	document.querySelector("button").addEventListener("click", () => {
	axios({
	url: "http://hmajax.itheima.net/api/register",
	method: "post",
	data: {
	username: "itheima666",
	password: "12345678",
	},
	})
	.then(result => {
	console.log(result);
	})
	.catch(error => {
	alert(error.response.data.message);
	});
	});
</script>

2.4 案例-用户登录

  • 样式
<!-- 引入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: 0.5s;
	opacity: 0;
	}
	.alert.show {
	opacity: 1;
	}
</style>
  • 框架
<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:点击登录时,用户名和密码长度判断,并提交数据和服务器通信
	function alertFn(msg, isSuccess) {
	// 显示提示框
	let myAlert = document.querySelector(".alert");
	myAlert.classList.add("show");
	// 更换样式
	let bgc = isSuccess ? "alert-success" : "alert-danger";
	myAlert.classList.add(bgc);
	// 打印信息
	myAlert.innerText = msg;
	// 2s后自动消失
	setTimeout(() => {
	myAlert.classList.remove("show");
	// 重置背景色,避免类名冲突
	myAlert.classList.remove(bgc);
	}, 2000);
	}
	document.querySelector(".btn-login").addEventListener("click", () => {
	let username = document.querySelector(".username").value;
	let password = document.querySelector(".password").value;
	if (username.length < 8) {
	// console.log('用户名不能少于8个字符')
	alertFn("用户名不能少于8个字符", false);
	return;
	}
	if (password < 6) {
	// console.log('密码不能少于6个字符')
	alertFn("密码不能少于6个字符", false);
	return;
	}
	axios({
	url: "http://hmajax.itheima.net/api/login",
	method: "post",
	data: {
	username,
	password,
	},
	})
	.then(result => {
	// alert(result.data.message)
	alertFn(result.data.message, true);
	})
	.catch(error => {
	// alert(error.response.data.message)
	alertFn(error.response.data.message, false);
	});
	});
</script>

2.5 form-serialize 插件

快速收集目标表单范围内表单元素的值

  • 引入 form-serialize 插件

  • 使用 serialize 函数

    • 参数 1:要获取的 form 表单标签对象(要求表单元素有 name 属性,用来作为收集的数据中属性名)

    • 参数 2:配置对象

      • hash:

        • true - 收集出来的是一个 JS 对象

        • false - 收集出来的是一个查询字符串

      • empty:

        • true - 收集空值

        • false - 不收集空值

  • 示例:收集登录表单里用户名和密码

<form action="javascript:;" class="example-form">
	<input type="text" name="uname" />
	<br />
	<input type="text" name="pwd" />
	<br />
	<input type="button" class="btn" value="提交" />
</form>
<!-- 
目标:在点击提交时,使用form-serialize插件,快速收集表单元素值
-->
<script src="./form-serialize.js"></script>
<script>
	document.querySelector(".btn").addEventListener("click", () => {
	const form = document.querySelector(".example-form");
	const data = serialize(form, { hash: true, empty: true });
	console.log(data);
	});
</script>

2.6 Bootstrap 弹框

2.6.1 属性控制

  • 引入 bootstrap.css 和 bootstrap.js

  • 准备弹框标签,确认结构(可以从 Bootstrap 官方文档的 Modal 里复制基础例子)- 运行到网页后,逐一对应标签和弹框每个部分对应关系

  • 通过自定义属性,通知弹框的显示和隐藏,语法如下:

<button data-bs-toggle="modal" data-bs-target="css选择器">显示弹框</button>
<button data-bs-dismiss="modal">Close</button>
  • 代码实现
<!-- 
目标:使用Bootstrap弹框
1. 引入bootstrap.css和bootstrap.js
2. 准备弹框标签,确认结构
3. 通过自定义属性,控制弹框的显示和隐藏
-->
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target=".mybox">显示弹框</button>
<div class="modal mybox" tabindex="-1">
	<div class="modal-dialog">
	<div class="modal-content">
	<div class="modal-header">
	<h5 class="modal-title">Modal title</h5>
	<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
	</div>
	<div class="modal-body">
	<p>Modal body text goes here.</p>
	</div>
	<div class="modal-footer">
	<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
	<button type="button" class="btn btn-primary">Save changes</button>
	</div>
	</div>
	</div>
</div>

2.6.2 js 控制

  • 为什么需要 js 方式控制?

    • 当显示/隐藏之前,需要执行一些 JS 逻辑代码,就需要引入 JS 控制弹框显示/隐藏的方式
  • 例如:

    • 点击编辑姓名按钮,在弹框显示之前,在输入框填入默认姓名

    • 点击保存按钮,在弹框隐藏之前,获取用户填入的名字并打印

  • 语法
// 创建弹框对象
const modalDom = document.querySelector("css选择器");
const modal = new bootstrap.Modal(modelDom);
// 显示弹框
modal.show();
// 隐藏弹框
modal.hide();
  • 示例
<!-- 
目标:使用JS控制弹框,显示和隐藏
1. 创建弹框对象
2. 调用弹框对象内置方法
.show() 显示
.hide() 隐藏
-->
<button type="button" class="btn btn-primary edit-btn">编辑姓名</button>
<div class="modal name-box" tabindex="-1">
	<div class="modal-dialog">
	<div class="modal-content">
	<div class="modal-header">
	<h5 class="modal-title">请输入姓名</h5>
	<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
	</div>
	<div class="modal-body">
	<form action="">
	<span>姓名:</span>
	<input type="text" class="username" />
	</form>
	</div>
	<div class="modal-footer">
	<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
	<button type="button" class="btn btn-primary save-btn">保存</button>
	</div>
	</div>
	</div>
</div>
<!-- 引入bootstrap.js -->
<script src="./bootstrap.min.js"></script>
<script>
	const modalBox = document.querySelector(".name-box");
	const modal = new bootstrap.Modal(modalBox);
	document.querySelector(".edit-btn").addEventListener("click", () => {
	document.querySelector(".username").value = "默认姓名";
	modal.show();
	});
	document.querySelector(".save-btn").addEventListener("click", () => {
	const username = document.querySelector(".username").value;
	console.log("将数据提交到服务器", username);
	modal.hide();
	});
</script>

2.7 案例-图书管理

<!-- 主体区域 -->
<div class="container">
	<!-- 头部标题和添加按钮 -->
	<div class="top">
	<h3>图书管理</h3>
	<button type="button" class="btn btn-primary plus-btn" data-bs-toggle="modal" data-bs-target=".add-modal">
	+ 添加
	</button>
	</div>
	<!-- 数据列表 -->
	<table class="table">
	<thead class="table-light">
	<tr>
	<th style="width: 150px;">序号</th>
	<th>书名</th>
	<th>作者</th>
	<th>出版社</th>
	<th style="width: 180px;">操作</th>
	</tr>
	</thead>
	<tbody class="list">
	<!-- <tr>
	<td>1</td>
	<td>JavaScript程序设计</td>
	<td>马特·弗里斯比</td>
	<td>人民邮电出版社</td>
	<td>
	<span class="del">删除</span>
	<span class="edit">编辑</span>
	</td>
	</tr> -->
	</tbody>
	</table>
</div>
<!-- 新增-弹出框 -->
<div class="modal fade add-modal">
	<!-- 中间白色区域 -->
	<div class="modal-dialog">
	<div class="modal-content">
	<div class="modal-header top">
	<span>添加图书</span>
	<button type="button" class="btn-close" aria-label="Close" data-bs-dismiss="modal"></button>
	</div>
	<div class="modal-body form-wrap">
	<!-- 新增表单 -->
	<form class="add-form">
	<div class="mb-3">
	<label for="bookname" class="form-label">书名</label>
	<input type="text" class="form-control bookname" placeholder="请输入书籍名称" name="bookname" />
	</div>
	<div class="mb-3">
	<label for="author" class="form-label">作者</label>
	<input type="text" class="form-control author" placeholder="请输入作者名称" name="author" />
	</div>
	<div class="mb-3">
	<label for="publisher" class="form-label">出版社</label>
	<input type="text" class="form-control publisher" placeholder="请输入出版社名称" name="publisher" />
	</div>
	</form>
	</div>
	<div class="modal-footer btn-group">
	<button type="button" class="btn btn-primary" data-bs-dismiss="modal">取消</button>
	<button type="button" class="btn btn-primary add-btn">保存</button>
	</div>
	</div>
	</div>
</div>
<!-- 编辑-弹出框 -->
<div class="modal fade edit-modal">
	<!-- 中间白色区域 -->
	<div class="modal-dialog">
	<div class="modal-content">
	<div class="modal-header top">
	<span>编辑图书</span>
	<button type="button" class="btn-close" aria-label="Close" data-bs-dismiss="modal"></button>
	</div>
	<div class="modal-body form-wrap">
	<!-- 编辑表单 -->
	<form class="edit-form">
	<!-- 保存正在编辑的图书id,隐藏起来:无需让用户修改 -->
	<input type="hidden" class="id" name="id" />
	<div class="mb-3">
	<label for="bookname" class="form-label">书名</label>
	<input type="text" class="form-control bookname" placeholder="请输入书籍名称" name="bookname" />
	</div>
	<div class="mb-3">
	<label for="author" class="form-label">作者</label>
	<input type="text" class="form-control author" placeholder="请输入作者名称" name="author" />
	</div>
	<div class="mb-3">
	<label for="publisher" class="form-label">出版社</label>
	<input type="text" class="form-control publisher" placeholder="请输入出版社名称" name="publisher" />
	</div>
	</form>
	</div>
	<div class="modal-footer btn-group">
	<button type="button" class="btn btn-primary" data-bs-dismiss="modal">取消</button>
	<button type="button" class="btn btn-primary edit-btn">修改</button>
	</div>
	</div>
	</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script>
<script src="./lib/form-serialize.js"></script>
<script src="./lib/bootstrap.min.js"></script>
<!-- 核心逻辑 -->
<script src="./js/index.js"></script>
  • index.js

  • 渲染图书列表

/**
 * 目标1:渲染图书列表
 * 1.1 获取数据
 * 1.2 渲染数据
 */
const creator = "老李";
function getBooksList() {
	// 1.1 获取数据
	axios({
	url: "http://hmajax.itheima.net/api/books",
	params: {
	creator,
	},
	}).then(result => {
	// console.log(result.data.data)
	// 1.2 渲染数据
	const list = result.data.data
	.map((item, index) => {
	return `
 <tr>
 <td>${index + 1}</td>
 <td>${item.bookname}</td>
 <td>${item.author}</td>
 <td>${item.publisher}</td>
 <td data-id=${item.id}>
 <span class="del">删除</span>
 <span class="edit">编辑</span>
 </td>
 </tr>
 `;
	})
	.join("");
	document.querySelector(".list").innerHTML = list;
	});
}
getBooksList();
  • 新增图书
/**
 * 目标2:新增图书
 * 2.1新增弹框->显示和隐藏
 * 2.2收集表单数据,并提交到服务器保存
 * 2.3刷新图书列表
 */
const addModalDom = document.querySelector(".add-modal");
const addModal = new bootstrap.Modal(addModalDom);
// 2.1 新增弹框->显示和隐藏
document.querySelector(".add-btn").addEventListener("click", () => {
	// 2.2 获取输入框的数据
	const addForm = document.querySelector(".add-form");
	const formData = serialize(addForm, { hash: true, empty: true });
	console.log(formData);
	// 2.3 提交到服务器保存
	axios({
	url: "http://hmajax.itheima.net/api/books",
	method: "post",
	data: {
	...formData,
	creator,
	},
	}).then(result => {
	console.log(result);
	// 2.4 重新渲染页面
	getBooksLis