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>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
    • 基本语法
    axios({
    url: "目标资源地址",
    }).then(result => {
    // 对服务器返回的数据做后续处理
    });
    axios({
      url: "目标资源地址",
    }).then(result => {
      // 对服务器返回的数据做后续处理
    });
    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>
<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>
<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 => {
// 对服务器返回的数据做后续处理
});
axios({
  url: "目标资源地址",
  params: {
    参数名: 值,
  },
}).then(result => {
  // 对服务器返回的数据做后续处理
});
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>
<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>
<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>
<!-- 样式 -->
<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>
<!-- 样式 --> <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 => {
// 对服务器返回的数据做后续处理
});
axios({
  url: "目标资源地址",
  method: "请求方法",
  data: {
    参数名: 值,
  },
}).then(result => {
  // 对服务器返回的数据做后续处理
});
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>
<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>
<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 => {
// 处理失败错误
});
axios({
  // ...请求选项
})
  .then(result => {
    // 处理成功数据
  })
  .catch(error => {
    // 处理失败错误
  });
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>
<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>
<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>
<!-- 引入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>
<!-- 引入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>
<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>
<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>
<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>
<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>
<button data-bs-toggle="modal" data-bs-target="css选择器">显示弹框</button>

<button data-bs-dismiss="modal">Close</button>
<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>
<!-- 
目标:使用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>
<!-- 目标:使用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();
// 创建弹框对象
const modalDom = document.querySelector("css选择器");
const modal = new bootstrap.Modal(modelDom);

// 显示弹框
modal.show();
// 隐藏弹框
modal.hide();
// 创建弹框对象 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>
<!-- 
目标:使用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>
<!-- 目标:使用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>
<!-- 主体区域 -->
<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>
<!-- 主体区域 --> <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();
/**
 * 目标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();
/** * 目标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 重新渲染页面
getBooksList();
// 重置表单
addForm.reset();
// 点击保存,隐藏模态框
addModal.hide();
});
});
/**
 * 目标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 重新渲染页面
    getBooksList();
    // 重置表单
    addForm.reset();
    // 点击保存,隐藏模态框
    addModal.hide();
  });
});
/** * 目标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 重新渲染页面 getBooksList(); // 重置表单 addForm.reset(); // 点击保存,隐藏模态框 addModal.hide(); }); });
  • 删除图书
/**
* 目标3:删除图书
* 3.1删除元素绑定点击事件->获取图书id
* 3.2调用删除接口
* 3.3刷新图书列表
*/
// 3.1 删除元素绑定点击事件(事件委托)->获取图书id
document.querySelector(".list").addEventListener("click", e => {
if (e.target.classList.contains("del")) {
const theId = e.target.parentNode.dataset.id;
// 3.2 调用删除接口
axios({
url: `http://hmajax.itheima.net/api/books/${theId}`,
method: "delete",
}).then(() => {
// 3.3 刷新图书列表
getBooksList();
});
}
});
/**
 * 目标3:删除图书
 *  3.1删除元素绑定点击事件->获取图书id
 *  3.2调用删除接口
 *  3.3刷新图书列表
 */
// 3.1 删除元素绑定点击事件(事件委托)->获取图书id
document.querySelector(".list").addEventListener("click", e => {
  if (e.target.classList.contains("del")) {
    const theId = e.target.parentNode.dataset.id;

    // 3.2 调用删除接口
    axios({
      url: `http://hmajax.itheima.net/api/books/${theId}`,
      method: "delete",
    }).then(() => {
      // 3.3 刷新图书列表
      getBooksList();
    });
  }
});
/** * 目标3:删除图书 * 3.1删除元素绑定点击事件->获取图书id * 3.2调用删除接口 * 3.3刷新图书列表 */ // 3.1 删除元素绑定点击事件(事件委托)->获取图书id document.querySelector(".list").addEventListener("click", e => { if (e.target.classList.contains("del")) { const theId = e.target.parentNode.dataset.id; // 3.2 调用删除接口 axios({ url: `http://hmajax.itheima.net/api/books/${theId}`, method: "delete", }).then(() => { // 3.3 刷新图书列表 getBooksList(); }); } });
  • 编辑图书
/**
* 目标4:编辑图书
* 4.1编辑弹框->显示和隐藏
* 4.2获取当前编辑图书数据->回显到编辑表单中
* 4.3提交保存修改,并刷新列表
*/
const editModalDom = document.querySelector(".edit-modal");
const editModal = new bootstrap.Modal(editModalDom);
document.querySelector(".list").addEventListener("click", e => {
if (e.target.classList.contains("edit")) {
const theId = e.target.parentNode.dataset.id;
// 4.2 获取当前编辑图书数据->回显到编辑表单中
axios({
url: `http://hmajax.itheima.net/api/books/${theId}`,
method: "get",
}).then(result => {
// 数据对象"属性"和标签"类名"一致
// 遍历数据对象,使用属性去获取对应的标签,快速赋值
const bookObj = result.data.data;
// console.log(bookObj)
const keys = Object.keys(bookObj);
keys.forEach(key => {
document.querySelector(`.edit-form .${key}`).value = bookObj[key];
});
});
// 4.1 编辑弹框->显示和隐藏
editModal.show();
}
});
document.querySelector(".edit-btn").addEventListener("click", () => {
const editForm = document.querySelector(".edit-form");
const editData = serialize(editForm, { hash: true, empty: true });
// 4.3 提交保存修改,并刷新列表
axios({
url: `http://hmajax.itheima.net/api/books/${editData.id}`,
method: "put",
data: {
...editData,
creator,
},
}).then(() => {
getBooksList();
});
editModal.hide();
});
/**
 * 目标4:编辑图书
 *  4.1编辑弹框->显示和隐藏
 *  4.2获取当前编辑图书数据->回显到编辑表单中
 *  4.3提交保存修改,并刷新列表
 */
const editModalDom = document.querySelector(".edit-modal");
const editModal = new bootstrap.Modal(editModalDom);

document.querySelector(".list").addEventListener("click", e => {
  if (e.target.classList.contains("edit")) {
    const theId = e.target.parentNode.dataset.id;
    // 4.2 获取当前编辑图书数据->回显到编辑表单中
    axios({
      url: `http://hmajax.itheima.net/api/books/${theId}`,
      method: "get",
    }).then(result => {
      // 数据对象"属性"和标签"类名"一致
      // 遍历数据对象,使用属性去获取对应的标签,快速赋值
      const bookObj = result.data.data;
      // console.log(bookObj)
      const keys = Object.keys(bookObj);
      keys.forEach(key => {
        document.querySelector(`.edit-form .${key}`).value = bookObj[key];
      });
    });
    // 4.1 编辑弹框->显示和隐藏
    editModal.show();
  }
});

document.querySelector(".edit-btn").addEventListener("click", () => {
  const editForm = document.querySelector(".edit-form");
  const editData = serialize(editForm, { hash: true, empty: true });

  // 4.3 提交保存修改,并刷新列表
  axios({
    url: `http://hmajax.itheima.net/api/books/${editData.id}`,
    method: "put",
    data: {
      ...editData,
      creator,
    },
  }).then(() => {
    getBooksList();
  });
  editModal.hide();
});
/** * 目标4:编辑图书 * 4.1编辑弹框->显示和隐藏 * 4.2获取当前编辑图书数据->回显到编辑表单中 * 4.3提交保存修改,并刷新列表 */ const editModalDom = document.querySelector(".edit-modal"); const editModal = new bootstrap.Modal(editModalDom); document.querySelector(".list").addEventListener("click", e => { if (e.target.classList.contains("edit")) { const theId = e.target.parentNode.dataset.id; // 4.2 获取当前编辑图书数据->回显到编辑表单中 axios({ url: `http://hmajax.itheima.net/api/books/${theId}`, method: "get", }).then(result => { // 数据对象"属性"和标签"类名"一致 // 遍历数据对象,使用属性去获取对应的标签,快速赋值 const bookObj = result.data.data; // console.log(bookObj) const keys = Object.keys(bookObj); keys.forEach(key => { document.querySelector(`.edit-form .${key}`).value = bookObj[key]; }); }); // 4.1 编辑弹框->显示和隐藏 editModal.show(); } }); document.querySelector(".edit-btn").addEventListener("click", () => { const editForm = document.querySelector(".edit-form"); const editData = serialize(editForm, { hash: true, empty: true }); // 4.3 提交保存修改,并刷新列表 axios({ url: `http://hmajax.itheima.net/api/books/${editData.id}`, method: "put", data: { ...editData, creator, }, }).then(() => { getBooksList(); }); editModal.hide(); });
  • 总结

    • 渲染列表(查)

      • 获取数据

      • 渲染数据

    • 新增图书(增)

      • 弹框(显示/隐藏)

      • 收集数据&提交保存

      • 刷新页面列表

    • 删除图书(删)

      • 绑定点击事件(获取要删除的图书 id)

      • 调用删除接口(让服务器删除此数据)

      • 成功后重新获取并刷新列表

    • 编辑图书(改)

      • 弹框(显示/隐藏)

      • 表单(数据回显)

      • 点击修改收集数据,提交到服务器保存

      • 重新获取并刷新列表

2.8 图片上传

把本地的图片上传到网页上显示

  • 实现步骤

    • 获取图片文件对象:e.target.files[0]

    • 使用 FormData 表单数据对象装入

      const fd = new FormData();
      fd.append(参数名, 值);
      const fd = new FormData();
      fd.append(参数名, 值);
      const fd = new FormData(); fd.append(参数名, 值);
    • 提交表单数据对象,使用服务器返回图片 url 网址

<!-- 文件选择元素 -->
<input type="file" class="upload" />
<img src="" />
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
document.querySelector(".upload").addEventListener("change", e => {
// 1. 获取图片文件
// console.log(e.target.files[0])
// 2. 使用 FormData 携带图片文件
const fd = new FormData();
fd.append("img", e.target.files[0]);
// 3. 提交到服务器,获取图片url网址使用
axios({
url: "http://hmajax.itheima.net/api/uploadimg",
method: "post",
data: fd,
}).then(result => {
// console.log(result)
document.querySelector("img").src = result.data.data.url;
});
});
</script>
<!-- 文件选择元素 -->
<input type="file" class="upload" />
<img src=""  />

<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  document.querySelector(".upload").addEventListener("change", e => {
    // 1. 获取图片文件
    // console.log(e.target.files[0])

    // 2. 使用 FormData 携带图片文件
    const fd = new FormData();
    fd.append("img", e.target.files[0]);

    // 3. 提交到服务器,获取图片url网址使用
    axios({
      url: "http://hmajax.itheima.net/api/uploadimg",
      method: "post",
      data: fd,
    }).then(result => {
      // console.log(result)
      document.querySelector("img").src = result.data.data.url;
    });
  });
</script>
<!-- 文件选择元素 --> <input type="file" class="upload" /> <img src="" /> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> document.querySelector(".upload").addEventListener("change", e => { // 1. 获取图片文件 // console.log(e.target.files[0]) // 2. 使用 FormData 携带图片文件 const fd = new FormData(); fd.append("img", e.target.files[0]); // 3. 提交到服务器,获取图片url网址使用 axios({ url: "http://hmajax.itheima.net/api/uploadimg", method: "post", data: fd, }).then(result => { // console.log(result) document.querySelector("img").src = result.data.data.url; }); }); </script>
  • 示例:更换背景图片
<div class="container">
<div class="nav">
<div class="left">
<ul>
<li><a href="http://yun.itheima.com/?webzly" target="_blank" rel="nofollow">免费教程</a></li>
<li><a href="http://resource.ityxb.com/booklist/?webzly" target="_blank" rel="nofollow">原创书籍</a></li>
<li>
<a href="http://www.itheima.com/teacher.html?webzly#ajavaee" target="_blank" rel="nofollow">教研团队</a>
</li>
<li>
<a href="http://www.itheima.com/special/hmschool/index.shtml?webzly" target="_blank" rel="nofollow">
校区汇总
</a>
</li>
<li><a href="http://www.itheima.com/flow/flow.html?webzly" target="_blank" rel="nofollow">报名流程</a></li>
<li><a href="https://pip.itcast.cn?hmgw$webzly" target="_blank" rel="nofollow">项目信息站</a></li>
<li><a href="http://bbs.itheima.com/forum.php?webzly" target="_blank" rel="nofollow">技术社区</a></li>
</ul>
</div>
<div class="right">
<label for="bg">更换背景</label>
<input class="bg-ipt" type="file" id="bg" />
</div>
</div>
<div class="search-container">
<img src="https://www.itheima.com/images/logo.png" />
<div class="search-box">
<input type="text" />
<button>搜索一下</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- 核心代码 -->
<script src="./js/index.js"></script>
<div class="container">
  <div class="nav">
    <div class="left">
      <ul>
        <li><a href="http://yun.itheima.com/?webzly" target="_blank" rel="nofollow">免费教程</a></li>
        <li><a href="http://resource.ityxb.com/booklist/?webzly" target="_blank" rel="nofollow">原创书籍</a></li>
        <li>
          <a href="http://www.itheima.com/teacher.html?webzly#ajavaee" target="_blank" rel="nofollow">教研团队</a>
        </li>
        <li>
          <a href="http://www.itheima.com/special/hmschool/index.shtml?webzly" target="_blank" rel="nofollow">
            校区汇总
          </a>
        </li>
        <li><a href="http://www.itheima.com/flow/flow.html?webzly" target="_blank" rel="nofollow">报名流程</a></li>
        <li><a href="https://pip.itcast.cn?hmgw$webzly" target="_blank" rel="nofollow">项目信息站</a></li>
        <li><a href="http://bbs.itheima.com/forum.php?webzly" target="_blank" rel="nofollow">技术社区</a></li>
      </ul>
    </div>
    <div class="right">
      <label for="bg">更换背景</label>
      <input class="bg-ipt" type="file" id="bg" />
    </div>
  </div>
  <div class="search-container">
    <img src="https://www.itheima.com/images/logo.png"  />
    <div class="search-box">
      <input type="text" />
      <button>搜索一下</button>
    </div>
  </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- 核心代码 -->
<script src="./js/index.js"></script>
<div class="container"> <div class="nav"> <div class="left"> <ul> <li><a href="http://yun.itheima.com/?webzly" target="_blank" rel="nofollow">免费教程</a></li> <li><a href="http://resource.ityxb.com/booklist/?webzly" target="_blank" rel="nofollow">原创书籍</a></li> <li> <a href="http://www.itheima.com/teacher.html?webzly#ajavaee" target="_blank" rel="nofollow">教研团队</a> </li> <li> <a href="http://www.itheima.com/special/hmschool/index.shtml?webzly" target="_blank" rel="nofollow"> 校区汇总 </a> </li> <li><a href="http://www.itheima.com/flow/flow.html?webzly" target="_blank" rel="nofollow">报名流程</a></li> <li><a href="https://pip.itcast.cn?hmgw$webzly" target="_blank" rel="nofollow">项目信息站</a></li> <li><a href="http://bbs.itheima.com/forum.php?webzly" target="_blank" rel="nofollow">技术社区</a></li> </ul> </div> <div class="right"> <label for="bg">更换背景</label> <input class="bg-ipt" type="file" id="bg" /> </div> </div> <div class="search-container"> <img src="https://www.itheima.com/images/logo.png" /> <div class="search-box"> <input type="text" /> <button>搜索一下</button> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <!-- 核心代码 --> <script src="./js/index.js"></script>
  • index.js
document.querySelector(".bg-ipt").addEventListener("change", e => {
// 1. 选择图片上传,设置body背景
const fd = new FormData();
fd.append("img", e.target.files[0]);
axios({
url: "http://hmajax.itheima.net/api/uploadimg",
method: "post",
data: fd,
}).then(result => {
// console.log(result)
const imgUrl = result.data.data.url;
document.body.style.backgroundImage = `url(${imgUrl})`;
// 2. 上传成功时,"保存"图片url网址
localStorage.setItem("bgImg", imgUrl);
});
});
// 3. 网页运行后,获取url网址使用
const imgUrl = localStorage.getItem("bgImg");
document.body.style.backgroundImage = `url(${imgUrl})`;
document.querySelector(".bg-ipt").addEventListener("change", e => {
  // 1. 选择图片上传,设置body背景
  const fd = new FormData();
  fd.append("img", e.target.files[0]);

  axios({
    url: "http://hmajax.itheima.net/api/uploadimg",
    method: "post",
    data: fd,
  }).then(result => {
    // console.log(result)
    const imgUrl = result.data.data.url;
    document.body.style.backgroundImage = `url(${imgUrl})`;

    // 2. 上传成功时,"保存"图片url网址
    localStorage.setItem("bgImg", imgUrl);
  });
});

// 3. 网页运行后,获取url网址使用
const imgUrl = localStorage.getItem("bgImg");
document.body.style.backgroundImage = `url(${imgUrl})`;
document.querySelector(".bg-ipt").addEventListener("change", e => { // 1. 选择图片上传,设置body背景 const fd = new FormData(); fd.append("img", e.target.files[0]); axios({ url: "http://hmajax.itheima.net/api/uploadimg", method: "post", data: fd, }).then(result => { // console.log(result) const imgUrl = result.data.data.url; document.body.style.backgroundImage = `url(${imgUrl})`; // 2. 上传成功时,"保存"图片url网址 localStorage.setItem("bgImg", imgUrl); }); }); // 3. 网页运行后,获取url网址使用 const imgUrl = localStorage.getItem("bgImg"); document.body.style.backgroundImage = `url(${imgUrl})`;

2.9 案例-个人信息设置

  • 结构
<!-- toast 提示框 -->
<div class="toast my-toast" data-bs-delay="1500">
<div class="toast-body">
<div class="alert alert-success info-box">
操作成功
</div>
</div>
</div>
<!-- 核心内容区域 -->
<div class="container">
<ul class="my-nav">
<li class="active">基本设置</li>
<li>安全设置</li>
<li>账号绑定</li>
<li>新消息通知</li>
</ul>
<div class="content">
<div class="info-wrap">
<h3 class="title">基本设置</h3>
<form class="user-form" action="javascript:;">
<div class="form-item">
<label for="email">邮箱</label>
<input id="email" name="email" class="email" type="text" placeholder="请输入邮箱" autocomplete="off">
</div>
<div class="form-item">
<label for="nickname">昵称</label>
<input id="nickname" name="nickname" class="nickname" type="text" placeholder="请输入昵称" autocomplete="off">
</div>
<div class="form-item">
<label>性别</label>
<label class="male-label"><input type="radio" name="gender" class="gender" value="0"></label>
<label class="male-label"><input type="radio" name="gender" class="gender" value="1"></label>
</div>
<div class="form-item">
<label for="desc">个人简介</label>
<textarea id="desc" name="desc" class="desc" placeholder="请输入个人简介" cols="20" rows="10" autocomplete="off"></textarea>
</div>
<button class="submit">提交</button>
</form>
</div>
<div class="avatar-box">
<h4 class="avatar-title">头像</h3>
<img class="prew" src="./img/头像.png" >
<label for="upload">更换头像</label>
<input id="upload" type="file" class="upload">
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js"></script>
<script src="./lib/form-serialize.js"></script>
<!-- 核心逻辑 -->
<script src="./js/index.js"></script>
<!-- toast 提示框 -->
<div class="toast my-toast" data-bs-delay="1500">
    <div class="toast-body">
        <div class="alert alert-success info-box">
            操作成功
        </div>
    </div>
</div>
<!-- 核心内容区域 -->
<div class="container">
    <ul class="my-nav">
        <li class="active">基本设置</li>
        <li>安全设置</li>
        <li>账号绑定</li>
        <li>新消息通知</li>
    </ul>
    <div class="content">
        <div class="info-wrap">
            <h3 class="title">基本设置</h3>
            <form class="user-form" action="javascript:;">
                <div class="form-item">
                    <label for="email">邮箱</label>
                    <input id="email" name="email" class="email" type="text" placeholder="请输入邮箱" autocomplete="off">
                </div>
                <div class="form-item">
                    <label for="nickname">昵称</label>
                    <input id="nickname" name="nickname" class="nickname" type="text" placeholder="请输入昵称" autocomplete="off">
                </div>
                <div class="form-item">
                    <label>性别</label>
                    <label class="male-label"><input type="radio" name="gender" class="gender" value="0">男</label>
                    <label class="male-label"><input type="radio" name="gender" class="gender" value="1">女</label>
                </div>
                <div class="form-item">
                    <label for="desc">个人简介</label>
                    <textarea id="desc" name="desc" class="desc" placeholder="请输入个人简介" cols="20" rows="10" autocomplete="off"></textarea>
                </div>
                <button class="submit">提交</button>
            </form>
        </div>
        <div class="avatar-box">
            <h4 class="avatar-title">头像</h3>
            <img class="prew" src="./img/头像.png" >
            <label for="upload">更换头像</label>
            <input id="upload" type="file" class="upload">
        </div>

    </div>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js"></script>
<script src="./lib/form-serialize.js"></script>
<!-- 核心逻辑 -->
<script src="./js/index.js"></script>
<!-- toast 提示框 --> <div class="toast my-toast" data-bs-delay="1500"> <div class="toast-body"> <div class="alert alert-success info-box"> 操作成功 </div> </div> </div> <!-- 核心内容区域 --> <div class="container"> <ul class="my-nav"> <li class="active">基本设置</li> <li>安全设置</li> <li>账号绑定</li> <li>新消息通知</li> </ul> <div class="content"> <div class="info-wrap"> <h3 class="title">基本设置</h3> <form class="user-form" action="javascript:;"> <div class="form-item"> <label for="email">邮箱</label> <input id="email" name="email" class="email" type="text" placeholder="请输入邮箱" autocomplete="off"> </div> <div class="form-item"> <label for="nickname">昵称</label> <input id="nickname" name="nickname" class="nickname" type="text" placeholder="请输入昵称" autocomplete="off"> </div> <div class="form-item"> <label>性别</label> <label class="male-label"><input type="radio" name="gender" class="gender" value="0">男</label> <label class="male-label"><input type="radio" name="gender" class="gender" value="1">女</label> </div> <div class="form-item"> <label for="desc">个人简介</label> <textarea id="desc" name="desc" class="desc" placeholder="请输入个人简介" cols="20" rows="10" autocomplete="off"></textarea> </div> <button class="submit">提交</button> </form> </div> <div class="avatar-box"> <h4 class="avatar-title">头像</h3> <img class="prew" src="./img/头像.png" > <label for="upload">更换头像</label> <input id="upload" type="file" class="upload"> </div> </div> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.min.js"></script> <script src="./lib/form-serialize.js"></script> <!-- 核心逻辑 --> <script src="./js/index.js"></script>
  • index.js

  • 信息渲染

/**
* 目标1:信息渲染
* 1.1 获取用户的数据
* 1.2 回显数据到标签上
* */
const creator = "小明";
axios({
url: "http://hmajax.itheima.net/api/settings",
params: {
creator,
},
}).then(result => {
// console.log(result.data.data)
const userObj = result.data.data;
const keys = Object.keys(userObj);
keys.forEach(key => {
// 头像和性别比较特殊,需要单独处理
if (key === "avatar") {
document.querySelector(".prew").src = userObj[key];
} else if (key === "gender") {
const gRadioList = document.querySelectorAll(".gender");
// 0男,1女,刚好与数组下标对应
const gNum = userObj[key];
gRadioList[gNum].checked = true;
} else {
document.querySelector(`.${key}`).value = userObj[key];
}
});
});
/**
 * 目标1:信息渲染
 *  1.1 获取用户的数据
 *  1.2 回显数据到标签上
 * */

const creator = "小明";
axios({
  url: "http://hmajax.itheima.net/api/settings",
  params: {
    creator,
  },
}).then(result => {
  // console.log(result.data.data)
  const userObj = result.data.data;

  const keys = Object.keys(userObj);
  keys.forEach(key => {
    // 头像和性别比较特殊,需要单独处理
    if (key === "avatar") {
      document.querySelector(".prew").src = userObj[key];
    } else if (key === "gender") {
      const gRadioList = document.querySelectorAll(".gender");
      // 0男,1女,刚好与数组下标对应
      const gNum = userObj[key];
      gRadioList[gNum].checked = true;
    } else {
      document.querySelector(`.${key}`).value = userObj[key];
    }
  });
});
/** * 目标1:信息渲染 * 1.1 获取用户的数据 * 1.2 回显数据到标签上 * */ const creator = "小明"; axios({ url: "http://hmajax.itheima.net/api/settings", params: { creator, }, }).then(result => { // console.log(result.data.data) const userObj = result.data.data; const keys = Object.keys(userObj); keys.forEach(key => { // 头像和性别比较特殊,需要单独处理 if (key === "avatar") { document.querySelector(".prew").src = userObj[key]; } else if (key === "gender") { const gRadioList = document.querySelectorAll(".gender"); // 0男,1女,刚好与数组下标对应 const gNum = userObj[key]; gRadioList[gNum].checked = true; } else { document.querySelector(`.${key}`).value = userObj[key]; } }); });
  • 修改头像
/**
* 目标2:修改头像
* 2.1 获取头像文件
* 2.2 提交服务器并更新头像
*/
document.querySelector(".upload").addEventListener("change", e => {
const fd = new FormData();
fd.append("img", e.target.files[0]);
fd.append("creator", creator);
axios({
url: "http://hmajax.itheima.net/api/avatar",
method: "put",
data: fd,
}).then(result => {
document.querySelector(".prew").src = result.data.data.avatar;
});
});
/**
 * 目标2:修改头像
 *  2.1 获取头像文件
 *  2.2 提交服务器并更新头像
 */

document.querySelector(".upload").addEventListener("change", e => {
  const fd = new FormData();
  fd.append("img", e.target.files[0]);
  fd.append("creator", creator);

  axios({
    url: "http://hmajax.itheima.net/api/avatar",
    method: "put",
    data: fd,
  }).then(result => {
    document.querySelector(".prew").src = result.data.data.avatar;
  });
});
/** * 目标2:修改头像 * 2.1 获取头像文件 * 2.2 提交服务器并更新头像 */ document.querySelector(".upload").addEventListener("change", e => { const fd = new FormData(); fd.append("img", e.target.files[0]); fd.append("creator", creator); axios({ url: "http://hmajax.itheima.net/api/avatar", method: "put", data: fd, }).then(result => { document.querySelector(".prew").src = result.data.data.avatar; }); });
  • 修改数据,并提示
/**
* 目标3:提交表单
* 3.1 收集表单信息
* 3.2 交到服务器保存
*/
/**
* 目标4:结果提示
* 4.1 创建toast对象
* 4.2 调用show方法->显示提示框
*/
document.querySelector(".submit").addEventListener("click", () => {
// 3.1 收集表单信息
const form = document.querySelector(".user-form");
const formData = serialize(form, { hash: true, empty: true });
formData.creator = creator;
formData.gender = +formData.gender;
// 3.2 提交到服务器保存
axios({
url: "http://hmajax.itheima.net/api/settings",
method: "put",
data: formData,
}).then(result => {
// 4.1 创建toast对象
const toastDom = document.querySelector(".my-toast");
const toast = new bootstrap.Toast(toastDom);
// 4.2 调用show方法->显示提示框
toast.show();
});
});
/**
 * 目标3:提交表单
 *  3.1 收集表单信息
 *  3.2 交到服务器保存
 */

/**
 * 目标4:结果提示
 *  4.1 创建toast对象
 *  4.2 调用show方法->显示提示框
 */

document.querySelector(".submit").addEventListener("click", () => {
  // 3.1 收集表单信息
  const form = document.querySelector(".user-form");
  const formData = serialize(form, { hash: true, empty: true });
  formData.creator = creator;
  formData.gender = +formData.gender;

  // 3.2 提交到服务器保存
  axios({
    url: "http://hmajax.itheima.net/api/settings",
    method: "put",
    data: formData,
  }).then(result => {
    // 4.1 创建toast对象
    const toastDom = document.querySelector(".my-toast");
    const toast = new bootstrap.Toast(toastDom);

    // 4.2 调用show方法->显示提示框
    toast.show();
  });
});
/** * 目标3:提交表单 * 3.1 收集表单信息 * 3.2 交到服务器保存 */ /** * 目标4:结果提示 * 4.1 创建toast对象 * 4.2 调用show方法->显示提示框 */ document.querySelector(".submit").addEventListener("click", () => { // 3.1 收集表单信息 const form = document.querySelector(".user-form"); const formData = serialize(form, { hash: true, empty: true }); formData.creator = creator; formData.gender = +formData.gender; // 3.2 提交到服务器保存 axios({ url: "http://hmajax.itheima.net/api/settings", method: "put", data: formData, }).then(result => { // 4.1 创建toast对象 const toastDom = document.querySelector(".my-toast"); const toast = new bootstrap.Toast(toastDom); // 4.2 调用show方法->显示提示框 toast.show(); }); });

2.10 请求方式别名

  • 为了方便起见,已经为所有支持的请求方法提供了别名
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.request(config)
axios.get(url[, config])
axios.delete(url[, config])
axios.head(url[, config])
axios.options(url[, config])
axios.post(url[, data[, config]])
axios.put(url[, data[, config]])
axios.request(config) axios.get(url[, config]) axios.delete(url[, config]) axios.head(url[, config]) axios.options(url[, config]) axios.post(url[, data[, config]]) axios.put(url[, data[, config]])
  • 注:在使用别名方法时, urlmethoddata 这些属性都不必在配置中指定

2.11 Axios API

2.11.1 axios 实例

可以使用自定义配置新建一个实例

const instance = axios.create({
baseURL: "https://some-domain.com/api/",
timeout: 1000,
headers: { "X-Custom-Header": "foobar" },
});
const instance = axios.create({
  baseURL: "https://some-domain.com/api/",
  timeout: 1000,
  headers: { "X-Custom-Header": "foobar" },
});
const instance = axios.create({ baseURL: "https://some-domain.com/api/", timeout: 1000, headers: { "X-Custom-Header": "foobar" }, });
  • 一些实例方法

    • axios#request(config)

    • axios#get(url[, config])

    • axios#delete(url[, config])

    • axios#head(url[, config])

    • axios#options(url[, config])

    • axios#post(url[, data[, config]])

    • axios#put(url[, data[, config]])

    • axios#patch(url[, data[, config]])

    • axios#getUri([config])

2.11.2 请求配置

  • 这些是创建请求时可以用的配置选项,只有url是必需的

  • 若没指定method,请求默认使用GET

{
// url:用于请求的服务器URL
url: '/user',
// method:创建请求时使用的方法,默认为get
method: 'get',
// baseURL:自动加在url前面,通过它可以传递相对地址
baseURL: 'https://some-domain.com/api/',
// transformRequest:允许在向服务器发送前,修改请求数据
// 它只能用于'PUT', 'POST'和'PATCH'这几个请求方法
// 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData或Stream
// 可以修改请求头
transformRequest: [function (data, headers) {
// 对发送的 data 进行任意转换处理
return data;
}],
// transformResponse:在传递给then/catch前,允许修改响应数据
transformResponse: [function (data) {
// 对接收的 data 进行任意转换处理
return data;
}],
// 自定义请求头
headers: {'X-Requested-With': 'XMLHttpRequest'},
// params:与请求一起发送的URL参数
// 必须是一个简单对象或URLSearchParams对象
params: {
ID: 12345
},
// data:作为请求体被发送的数据
// 仅适用'PUT', 'POST', 'DELETE'和'PATCH'请求方法
// 在没有设置`transformRequest`时,则必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属: FormData, File, Blob
// - Node 专属: Stream, Buffer
data: {
firstName: 'Fred'
},
// 发送请求体数据的可选语法
// 请求方式 post
// 只有 value 会被发送,key 则不会
data: 'Country=Brasil&City=Belo Horizonte',
// timeout:指定请求超时的毫秒数
// 如果请求时间超过`timeout`的值,则请求会被中断,默认为0,表示永不超时
timeout: 1000,
// withCredentials:表示跨域请求时是否需要使用凭证,默认false
withCredentials: false,
// adapter:允许自定义处理请求,这使测试更加容易
// 返回一个`promise`并提供一个有效的响应(参见 lib/adapters/README.md)
adapter: function (config) {
/* ... */
},
// auth:HTTP Basic Auth
auth: {
username: 'janedoe',
password: 's00pers3cret'
},
// responseType:浏览器将要响应的数据类型
// 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
// 浏览器专属:'blob'
responseType: 'json', // 默认值
// responseEncoding:用于解码响应的编码 (Node.js专属)
// 注意:忽略`responseType`的值为 'stream',或者是客户端请求
responseEncoding: 'utf8', // 默认值
// `xsrfCookieName`是`xsrf token`的值,被用作`cookie`的名称
xsrfCookieName: 'XSRF-TOKEN', // 默认值
// `xsrfHeaderName`是带有`xsrf token`值的http请求头名称
xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值
// `onUploadProgress`允许为上传处理进度事件(浏览器专属)
onUploadProgress: function (progressEvent) {
// 处理原生进度事件
},
// `onDownloadProgress`允许为下载处理进度事件(浏览器专属)
onDownloadProgress: function (progressEvent) {
// 处理原生进度事件
},
// `maxContentLength`定义了node.js中允许的HTTP响应内容的最大字节数
maxContentLength: 2000,
// `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
maxBodyLength: 2000,
// `validateStatus`定义了对于给定的HTTP状态码是 resolve 还是 reject promise
// 返回`true`(或者设置为`null`或`undefined`),则promise将会resolved,否则是rejected
validateStatus: function (status) {
return status >= 200 && status < 300; // 默认值
},
// maxRedirects:定义了在node.js中要遵循的最大重定向数,设置为0,则不会进行重定向
maxRedirects: 5, // 默认值
// `socketPath` 定义了在node.js中使用的UNIX套接字
// e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程
// 只能指定 `socketPath` 或 `proxy`
// 若都指定,则使用 `socketPath`
socketPath: null, // default
// `httpAgent`和`httpsAgent`分别定义了在 node.js 中执行 http 和 https 请求时使用的自定义代理
// 这样就可以添加默认情况下未启用的选项,如`keepAlive`
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// `proxy` 定义了代理服务器的主机名,端口和协议
// 可以使用常规的`http_proxy`和`https_proxy` 环境变量
// 使用`false`可以禁用代理功能,同时环境变量也会被忽略
// `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据
// 这将设置一个`Proxy-Authorization`请求头,它会覆盖`headers`中已存在的自定义`Proxy-Authorization`请求头
// 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`
proxy: {
protocol: 'https',
host: '127.0.0.1',
port: 9000,
auth: {
username: 'mikeymike',
password: 'rapunz3l'
}
},
// 详见https://axios-http.com/zh/docs/cancellation
cancelToken: new CancelToken(function (cancel) {
}),
// `decompress`:表示是否要自动解压缩响应正文
// 将其设置为"false",它不会解压缩响应,并会保留原始的"Content-Encoding"标头
// 如果设置为“true”,将从所有解压缩响应的响应对象中移除"Content-Encoding"标头
// - 仅适用于Node (XHR 无法关闭解压缩功能)
decompress: true // 默认值
}
{
  // url:用于请求的服务器URL
  url: '/user',

  // method:创建请求时使用的方法,默认为get
  method: 'get',

  // baseURL:自动加在url前面,通过它可以传递相对地址
  baseURL: 'https://some-domain.com/api/',

  // transformRequest:允许在向服务器发送前,修改请求数据
  // 它只能用于'PUT', 'POST'和'PATCH'这几个请求方法
  // 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData或Stream
  // 可以修改请求头
  transformRequest: [function (data, headers) {
    // 对发送的 data 进行任意转换处理

    return data;
  }],

  // transformResponse:在传递给then/catch前,允许修改响应数据
  transformResponse: [function (data) {
    // 对接收的 data 进行任意转换处理

    return data;
  }],

  // 自定义请求头
  headers: {'X-Requested-With': 'XMLHttpRequest'},

  // params:与请求一起发送的URL参数
  // 必须是一个简单对象或URLSearchParams对象
  params: {
    ID: 12345
  },

  // data:作为请求体被发送的数据
  // 仅适用'PUT', 'POST', 'DELETE'和'PATCH'请求方法
  // 在没有设置`transformRequest`时,则必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属: FormData, File, Blob
  // - Node 专属: Stream, Buffer
  data: {
    firstName: 'Fred'
  },

  // 发送请求体数据的可选语法
  // 请求方式 post
  // 只有 value 会被发送,key 则不会
  data: 'Country=Brasil&City=Belo Horizonte',

  // timeout:指定请求超时的毫秒数
  // 如果请求时间超过`timeout`的值,则请求会被中断,默认为0,表示永不超时
  timeout: 1000,

  // withCredentials:表示跨域请求时是否需要使用凭证,默认false
  withCredentials: false,

  // adapter:允许自定义处理请求,这使测试更加容易
  // 返回一个`promise`并提供一个有效的响应(参见 lib/adapters/README.md)
  adapter: function (config) {
    /* ... */
  },

  // auth:HTTP Basic Auth
  auth: {
    username: 'janedoe',
    password: 's00pers3cret'
  },

  // responseType:浏览器将要响应的数据类型
  // 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream'
  // 浏览器专属:'blob'
  responseType: 'json', // 默认值

  // responseEncoding:用于解码响应的编码 (Node.js专属)
  // 注意:忽略`responseType`的值为 'stream',或者是客户端请求
  responseEncoding: 'utf8', // 默认值

  // `xsrfCookieName`是`xsrf token`的值,被用作`cookie`的名称
  xsrfCookieName: 'XSRF-TOKEN', // 默认值

  // `xsrfHeaderName`是带有`xsrf token`值的http请求头名称
  xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值

  // `onUploadProgress`允许为上传处理进度事件(浏览器专属)
  onUploadProgress: function (progressEvent) {
    // 处理原生进度事件
  },

  // `onDownloadProgress`允许为下载处理进度事件(浏览器专属)
  onDownloadProgress: function (progressEvent) {
    // 处理原生进度事件
  },

  // `maxContentLength`定义了node.js中允许的HTTP响应内容的最大字节数
  maxContentLength: 2000,

  // `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数
  maxBodyLength: 2000,

  // `validateStatus`定义了对于给定的HTTP状态码是 resolve 还是 reject promise
  // 返回`true`(或者设置为`null`或`undefined`),则promise将会resolved,否则是rejected
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认值
  },

  // maxRedirects:定义了在node.js中要遵循的最大重定向数,设置为0,则不会进行重定向
  maxRedirects: 5, // 默认值

  // `socketPath` 定义了在node.js中使用的UNIX套接字
  // e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程
  // 只能指定 `socketPath` 或 `proxy`
  // 若都指定,则使用 `socketPath`
  socketPath: null, // default

  // `httpAgent`和`httpsAgent`分别定义了在 node.js 中执行 http 和 https 请求时使用的自定义代理
  // 这样就可以添加默认情况下未启用的选项,如`keepAlive`
  httpAgent: new http.Agent({ keepAlive: true }),
  httpsAgent: new https.Agent({ keepAlive: true }),

  // `proxy` 定义了代理服务器的主机名,端口和协议
  // 可以使用常规的`http_proxy`和`https_proxy` 环境变量
  // 使用`false`可以禁用代理功能,同时环境变量也会被忽略
  // `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据
  // 这将设置一个`Proxy-Authorization`请求头,它会覆盖`headers`中已存在的自定义`Proxy-Authorization`请求头
  // 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https`
  proxy: {
    protocol: 'https',
    host: '127.0.0.1',
    port: 9000,
    auth: {
      username: 'mikeymike',
      password: 'rapunz3l'
    }
  },

  // 详见https://axios-http.com/zh/docs/cancellation
  cancelToken: new CancelToken(function (cancel) {
  }),

  // `decompress`:表示是否要自动解压缩响应正文
  // 将其设置为"false",它不会解压缩响应,并会保留原始的"Content-Encoding"标头
  // 如果设置为“true”,将从所有解压缩响应的响应对象中移除"Content-Encoding"标头
  // - 仅适用于Node (XHR 无法关闭解压缩功能)
  decompress: true // 默认值
}
{ // url:用于请求的服务器URL url: '/user', // method:创建请求时使用的方法,默认为get method: 'get', // baseURL:自动加在url前面,通过它可以传递相对地址 baseURL: 'https://some-domain.com/api/', // transformRequest:允许在向服务器发送前,修改请求数据 // 它只能用于'PUT', 'POST'和'PATCH'这几个请求方法 // 数组中最后一个函数必须返回一个字符串, 一个Buffer实例,ArrayBuffer,FormData或Stream // 可以修改请求头 transformRequest: [function (data, headers) { // 对发送的 data 进行任意转换处理 return data; }], // transformResponse:在传递给then/catch前,允许修改响应数据 transformResponse: [function (data) { // 对接收的 data 进行任意转换处理 return data; }], // 自定义请求头 headers: {'X-Requested-With': 'XMLHttpRequest'}, // params:与请求一起发送的URL参数 // 必须是一个简单对象或URLSearchParams对象 params: { ID: 12345 }, // data:作为请求体被发送的数据 // 仅适用'PUT', 'POST', 'DELETE'和'PATCH'请求方法 // 在没有设置`transformRequest`时,则必须是以下类型之一: // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams // - 浏览器专属: FormData, File, Blob // - Node 专属: Stream, Buffer data: { firstName: 'Fred' }, // 发送请求体数据的可选语法 // 请求方式 post // 只有 value 会被发送,key 则不会 data: 'Country=Brasil&City=Belo Horizonte', // timeout:指定请求超时的毫秒数 // 如果请求时间超过`timeout`的值,则请求会被中断,默认为0,表示永不超时 timeout: 1000, // withCredentials:表示跨域请求时是否需要使用凭证,默认false withCredentials: false, // adapter:允许自定义处理请求,这使测试更加容易 // 返回一个`promise`并提供一个有效的响应(参见 lib/adapters/README.md) adapter: function (config) { /* ... */ }, // auth:HTTP Basic Auth auth: { username: 'janedoe', password: 's00pers3cret' }, // responseType:浏览器将要响应的数据类型 // 选项包括: 'arraybuffer', 'document', 'json', 'text', 'stream' // 浏览器专属:'blob' responseType: 'json', // 默认值 // responseEncoding:用于解码响应的编码 (Node.js专属) // 注意:忽略`responseType`的值为 'stream',或者是客户端请求 responseEncoding: 'utf8', // 默认值 // `xsrfCookieName`是`xsrf token`的值,被用作`cookie`的名称 xsrfCookieName: 'XSRF-TOKEN', // 默认值 // `xsrfHeaderName`是带有`xsrf token`值的http请求头名称 xsrfHeaderName: 'X-XSRF-TOKEN', // 默认值 // `onUploadProgress`允许为上传处理进度事件(浏览器专属) onUploadProgress: function (progressEvent) { // 处理原生进度事件 }, // `onDownloadProgress`允许为下载处理进度事件(浏览器专属) onDownloadProgress: function (progressEvent) { // 处理原生进度事件 }, // `maxContentLength`定义了node.js中允许的HTTP响应内容的最大字节数 maxContentLength: 2000, // `maxBodyLength`(仅Node)定义允许的http请求内容的最大字节数 maxBodyLength: 2000, // `validateStatus`定义了对于给定的HTTP状态码是 resolve 还是 reject promise // 返回`true`(或者设置为`null`或`undefined`),则promise将会resolved,否则是rejected validateStatus: function (status) { return status >= 200 && status < 300; // 默认值 }, // maxRedirects:定义了在node.js中要遵循的最大重定向数,设置为0,则不会进行重定向 maxRedirects: 5, // 默认值 // `socketPath` 定义了在node.js中使用的UNIX套接字 // e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程 // 只能指定 `socketPath` 或 `proxy` // 若都指定,则使用 `socketPath` socketPath: null, // default // `httpAgent`和`httpsAgent`分别定义了在 node.js 中执行 http 和 https 请求时使用的自定义代理 // 这样就可以添加默认情况下未启用的选项,如`keepAlive` httpAgent: new http.Agent({ keepAlive: true }), httpsAgent: new https.Agent({ keepAlive: true }), // `proxy` 定义了代理服务器的主机名,端口和协议 // 可以使用常规的`http_proxy`和`https_proxy` 环境变量 // 使用`false`可以禁用代理功能,同时环境变量也会被忽略 // `auth`表示应使用HTTP Basic auth连接到代理,并且提供凭据 // 这将设置一个`Proxy-Authorization`请求头,它会覆盖`headers`中已存在的自定义`Proxy-Authorization`请求头 // 如果代理服务器使用 HTTPS,则必须设置 protocol 为`https` proxy: { protocol: 'https', host: '127.0.0.1', port: 9000, auth: { username: 'mikeymike', password: 'rapunz3l' } }, // 详见https://axios-http.com/zh/docs/cancellation cancelToken: new CancelToken(function (cancel) { }), // `decompress`:表示是否要自动解压缩响应正文 // 将其设置为"false",它不会解压缩响应,并会保留原始的"Content-Encoding"标头 // 如果设置为“true”,将从所有解压缩响应的响应对象中移除"Content-Encoding"标头 // - 仅适用于Node (XHR 无法关闭解压缩功能) decompress: true // 默认值 }

2.11.3 响应结构

  • 一个请求的响应包含以下信息
{
// data:由服务器提供的响应
data: {},
// status:来自服务器响应的 HTTP 状态码
status: 200,
// statusText:来自服务器响应的 HTTP 状态信息
statusText: 'OK',
// headers:服务器响应头
// 所有 header 名称都是小写,且可以使用方括号语法访问
// 例如: `response.headers['content-type']`
headers: {},
// config:是`axios`请求的配置信息
config: {},
// request:是生成此响应的请求
// 在node.js中它是最后一个ClientRequest实例 (in redirects),
// 在浏览器中则是 XMLHttpRequest 实例
request: {}
}
{
  // data:由服务器提供的响应
  data: {},

  // status:来自服务器响应的 HTTP 状态码
  status: 200,

  // statusText:来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // headers:服务器响应头
  // 所有 header 名称都是小写,且可以使用方括号语法访问
  // 例如: `response.headers['content-type']`
  headers: {},

  // config:是`axios`请求的配置信息
  config: {},

  // request:是生成此响应的请求
  // 在node.js中它是最后一个ClientRequest实例 (in redirects),
  // 在浏览器中则是 XMLHttpRequest 实例
  request: {}
}
{ // data:由服务器提供的响应 data: {}, // status:来自服务器响应的 HTTP 状态码 status: 200, // statusText:来自服务器响应的 HTTP 状态信息 statusText: 'OK', // headers:服务器响应头 // 所有 header 名称都是小写,且可以使用方括号语法访问 // 例如: `response.headers['content-type']` headers: {}, // config:是`axios`请求的配置信息 config: {}, // request:是生成此响应的请求 // 在node.js中它是最后一个ClientRequest实例 (in redirects), // 在浏览器中则是 XMLHttpRequest 实例 request: {} }

2.11.4 默认配置

️ 全局 axios 默认值
axios.defaults.baseURL = "https://api.example.com";
axios.defaults.headers.common["Authorization"] = AUTH_TOKEN;
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
axios.defaults.baseURL = "https://api.example.com";
axios.defaults.headers.common["Authorization"] = AUTH_TOKEN;
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
axios.defaults.baseURL = "https://api.example.com"; axios.defaults.headers.common["Authorization"] = AUTH_TOKEN; axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
️ 自定义实例默认值
// 创建实例时配置默认值
const instance = axios.create({
baseURL: "https://api.example.com",
});
// 创建实例后修改默认值
instance.defaults.headers.common["Authorization"] = AUTH_TOKEN;
// 创建实例时配置默认值
const instance = axios.create({
  baseURL: "https://api.example.com",
});

// 创建实例后修改默认值
instance.defaults.headers.common["Authorization"] = AUTH_TOKEN;
// 创建实例时配置默认值 const instance = axios.create({ baseURL: "https://api.example.com", }); // 创建实例后修改默认值 instance.defaults.headers.common["Authorization"] = AUTH_TOKEN;
️ 配置的优先级
  • 配置将会按优先级进行合并

  • 它的顺序是:在lib/defaults.js中找到的库默认值,然后是实例的 defaults 属性,最后是请求的config参数,后面的优先级要高于前面的

// 使用库提供的默认配置创建实例
// 此时超时配置的默认值是 `0`
const instance = axios.create();
// 重写库的超时默认值
// 现在,所有使用此实例的请求都将等待2.5秒,然后才会超时
instance.defaults.timeout = 2500;
// 重写此请求的超时时间,因为该请求需要很长时间
instance.get("/longRequest", {
timeout: 5000,
});
// 使用库提供的默认配置创建实例
// 此时超时配置的默认值是 `0`
const instance = axios.create();

// 重写库的超时默认值
// 现在,所有使用此实例的请求都将等待2.5秒,然后才会超时
instance.defaults.timeout = 2500;

// 重写此请求的超时时间,因为该请求需要很长时间
instance.get("/longRequest", {
  timeout: 5000,
});
// 使用库提供的默认配置创建实例 // 此时超时配置的默认值是 `0` const instance = axios.create(); // 重写库的超时默认值 // 现在,所有使用此实例的请求都将等待2.5秒,然后才会超时 instance.defaults.timeout = 2500; // 重写此请求的超时时间,因为该请求需要很长时间 instance.get("/longRequest", { timeout: 5000, });

2.11.5 拦截器

  • 在请求或响应被 then 或 catch 处理前拦截它们
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么
return config;
},
function (error) {
// 对请求错误做些什么
return Promise.reject(error);
}
);
// 添加响应拦截器
axios.interceptors.response.use(
function (response) {
// 2xx 范围内的状态码都会触发该函数
// 对响应数据做点什么
return response;
},
function (error) {
// 超出 2xx 范围的状态码都会触发该函数
// 对响应错误做点什么
return Promise.reject(error);
}
);
// 添加请求拦截器
axios.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    return config;
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 添加响应拦截器
axios.interceptors.response.use(
  function (response) {
    // 2xx 范围内的状态码都会触发该函数
    // 对响应数据做点什么
    return response;
  },
  function (error) {
    // 超出 2xx 范围的状态码都会触发该函数
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
// 添加请求拦截器 axios.interceptors.request.use( function (config) { // 在发送请求之前做些什么 return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); } ); // 添加响应拦截器 axios.interceptors.response.use( function (response) { // 2xx 范围内的状态码都会触发该函数 // 对响应数据做点什么 return response; }, function (error) { // 超出 2xx 范围的状态码都会触发该函数 // 对响应错误做点什么 return Promise.reject(error); } );
  • 移除拦截器
const myInterceptor = axios.interceptors.request.use(function () {
/*...*/
});
axios.interceptors.request.eject(myInterceptor);
const myInterceptor = axios.interceptors.request.use(function () {
  /*...*/
});
axios.interceptors.request.eject(myInterceptor);
const myInterceptor = axios.interceptors.request.use(function () { /*...*/ }); axios.interceptors.request.eject(myInterceptor);
  • 可以给自定义的 axios 实例添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {
/*...*/
});
const instance = axios.create();
instance.interceptors.request.use(function () {
  /*...*/
});
const instance = axios.create(); instance.interceptors.request.use(function () { /*...*/ });

2.11.6 错误处理

axios.get("/user/12345").catch(function (error) {
if (error.response) {
// 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
// 请求已经成功发起,但没有收到响应
// `error.request` 在浏览器中是 XMLHttpRequest 的实例,
// 而在node.js中是 http.ClientRequest 的实例
console.log(error.request);
} else {
// 发送请求时出了点问题
console.log("Error", error.message);
}
console.log(error.config);
});
axios.get("/user/12345").catch(function (error) {
  if (error.response) {
    // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
    console.log(error.response.data);
    console.log(error.response.status);
    console.log(error.response.headers);
  } else if (error.request) {
    // 请求已经成功发起,但没有收到响应
    // `error.request` 在浏览器中是 XMLHttpRequest 的实例,
    // 而在node.js中是 http.ClientRequest 的实例
    console.log(error.request);
  } else {
    // 发送请求时出了点问题
    console.log("Error", error.message);
  }
  console.log(error.config);
});
axios.get("/user/12345").catch(function (error) { if (error.response) { // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围 console.log(error.response.data); console.log(error.response.status); console.log(error.response.headers); } else if (error.request) { // 请求已经成功发起,但没有收到响应 // `error.request` 在浏览器中是 XMLHttpRequest 的实例, // 而在node.js中是 http.ClientRequest 的实例 console.log(error.request); } else { // 发送请求时出了点问题 console.log("Error", error.message); } console.log(error.config); });
  • 使用 validateStatus 配置选项,可以自定义抛出错误的 HTTP code
axios.get("/user/12345", {
validateStatus: function (status) {
return status < 500; // 处理状态码小于500的情况
},
});
axios.get("/user/12345", {
  validateStatus: function (status) {
    return status < 500; // 处理状态码小于500的情况
  },
});
axios.get("/user/12345", { validateStatus: function (status) { return status < 500; // 处理状态码小于500的情况 }, });
  • 使用 toJSON 可以获取更多关于 HTTP 错误的信息
axios.get("/user/12345").catch(function (error) {
console.log(error.toJSON());
});
axios.get("/user/12345").catch(function (error) {
  console.log(error.toJSON());
});
axios.get("/user/12345").catch(function (error) { console.log(error.toJSON()); });

2.11.7 取消请求

️ AbortController
const controller = new AbortController();
axios
.get("/foo/bar", {
signal: controller.signal,
})
.then(function (response) {
//...
});
// 取消请求
controller.abort();
const controller = new AbortController();

axios
  .get("/foo/bar", {
    signal: controller.signal,
  })
  .then(function (response) {
    //...
  });
// 取消请求
controller.abort();
const controller = new AbortController(); axios .get("/foo/bar", { signal: controller.signal, }) .then(function (response) { //... }); // 取消请求 controller.abort();

2.11.8 请求体编码

  • 默认情况下,axios 将 JavaScript 对象序列化为JSON。 要以application/x-www-form-urlencoded格式发送数据
️ 浏览器
  • URLSearchParams
const params = new URLSearchParams();
params.append("param1", "value1");
params.append("param2", "value2");
axios.post("/foo", params);
const params = new URLSearchParams();
params.append("param1", "value1");
params.append("param2", "value2");
axios.post("/foo", params);
const params = new URLSearchParams(); params.append("param1", "value1"); params.append("param2", "value2"); axios.post("/foo", params);
  • 注:不是所有的浏览器都支持 URLSearchParams ,但是可以使用polyfill (确保 polyfill 全局环境)

  • 可以使用qs 库编码数据

import qs from "qs";
const data = { bar: 123 };
const options = {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
data: qs.stringify(data),
url,
};
axios(options);
import qs from "qs";
const data = { bar: 123 };
const options = {
  method: "POST",
  headers: { "content-type": "application/x-www-form-urlencoded" },
  data: qs.stringify(data),
  url,
};
axios(options);
import qs from "qs"; const data = { bar: 123 }; const options = { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, data: qs.stringify(data), url, }; axios(options);
️ Node.js
  • 在 node.js 中, 可以使用querystring 模块
const querystring = require("querystring");
axios.post("http://something.com/", querystring.stringify({ foo: "bar" }));
const querystring = require("querystring");
axios.post("http://something.com/", querystring.stringify({ foo: "bar" }));
const querystring = require("querystring"); axios.post("http://something.com/", querystring.stringify({ foo: "bar" }));
  • 或者从’url module’中使用’URLSearchParams’
const url = require("url");
const params = new url.URLSearchParams({ foo: "bar" });
axios.post("http://something.com/", params.toString());
const url = require("url");
const params = new url.URLSearchParams({ foo: "bar" });
axios.post("http://something.com/", params.toString());
const url = require("url"); const params = new url.URLSearchParams({ foo: "bar" }); axios.post("http://something.com/", params.toString());
  • 也可以使用 qs 库

  • Form data

const FormData = require("form-data");
const form = new FormData();
form.append("my_field", "my value");
form.append("my_buffer", new Buffer(10));
form.append("my_file", fs.createReadStream("/foo/bar.jpg"));
axios.post("https://example.com", form, { headers: form.getHeaders() });
const FormData = require("form-data");

const form = new FormData();
form.append("my_field", "my value");
form.append("my_buffer", new Buffer(10));
form.append("my_file", fs.createReadStream("/foo/bar.jpg"));

axios.post("https://example.com", form, { headers: form.getHeaders() });
const FormData = require("form-data"); const form = new FormData(); form.append("my_field", "my value"); form.append("my_buffer", new Buffer(10)); form.append("my_file", fs.createReadStream("/foo/bar.jpg")); axios.post("https://example.com", form, { headers: form.getHeaders() });
  • 或者, 使用一个拦截器
axios.interceptors.request.use(config => {
if (config.data instanceof FormData) {
Object.assign(config.headers, config.data.getHeaders());
}
return config;
});
axios.interceptors.request.use(config => {
  if (config.data instanceof FormData) {
    Object.assign(config.headers, config.data.getHeaders());
  }
  return config;
});
axios.interceptors.request.use(config => { if (config.data instanceof FormData) { Object.assign(config.headers, config.data.getHeaders()); } return config; });

2.11.9 axios 二次封装

  • 为什么

    • 方便管理和维护

    • 请求的 url 地址统一管理

    • 某些接口需要传递 headers

  • request.js

// 1. 引入axios
import axios from 'axios';
// 2. 创建axios对象
const service = axios.create();
// 3. 请求拦截器(前端给后端发送数据,没有到后端)
// 做的事:headers给后端传递token
service.interceptors.request.use(
config => {
return config;
}, error => {
Promise.reject(error);
}
});
// 4.响应拦截器(后端给前端返回数据,前端到后端了)
service.interceptors.response.use(
(response) => {
// 这里是对响应的简化 data = response.data
const { data, meta } = response.data
if (meta.status === 200 || meta.status === 201){
//回传的数据
return data
} else {
ElMessage.error(meta.msg)
return Promise.reject(new Error(meta.msg))
}
},
error => {
error.response && ElMessage.error(error.response.data)
return Promise.reject(new Error(error.response.data))
}
)
export default service
// 1. 引入axios
import axios from 'axios';
// 2. 创建axios对象
const service = axios.create();
// 3. 请求拦截器(前端给后端发送数据,没有到后端)
// 做的事:headers给后端传递token
service.interceptors.request.use(
    config => {
      return config;
  }, error => {
        Promise.reject(error);
  }
});
// 4.响应拦截器(后端给前端返回数据,前端到后端了)
service.interceptors.response.use(
    (response) => {
        // 这里是对响应的简化 data = response.data
        const { data, meta } = response.data
        if (meta.status === 200 || meta.status === 201){
            //回传的数据
            return data
        } else {
            ElMessage.error(meta.msg)
            return Promise.reject(new Error(meta.msg))
        }
    },
    error => {
        error.response && ElMessage.error(error.response.data)
        return Promise.reject(new Error(error.response.data))
    }
)
export default service
// 1. 引入axios import axios from 'axios'; // 2. 创建axios对象 const service = axios.create(); // 3. 请求拦截器(前端给后端发送数据,没有到后端) // 做的事:headers给后端传递token service.interceptors.request.use( config => { return config; }, error => { Promise.reject(error); } }); // 4.响应拦截器(后端给前端返回数据,前端到后端了) service.interceptors.response.use( (response) => { // 这里是对响应的简化 data = response.data const { data, meta } = response.data if (meta.status === 200 || meta.status === 201){ //回传的数据 return data } else { ElMessage.error(meta.msg) return Promise.reject(new Error(meta.msg)) } }, error => { error.response && ElMessage.error(error.response.data) return Promise.reject(new Error(error.response.data)) } ) export default service

2.11.10 API 解耦

  • 封装
import request from "@/utils/request";
export function getsliders() {
return request({
url: "/api/slider/getsliders",
});
}
import request from "@/utils/request";
export function getsliders() {
  return request({
    url: "/api/slider/getsliders",
  });
}
import request from "@/utils/request"; export function getsliders() { return request({ url: "/api/slider/getsliders", }); }
  • 使用
<script type="text/javascript">
import {getSliders} from '@/utils/api/course'
export default{
data (){
return {
list:[]
}
},
created() {
getsliders().then (res=>{
console.log(res)
})
}
</script>
<script type="text/javascript">
  import {getSliders} from '@/utils/api/course'
  export default{
      data (){
          return {
              list:[]
          }
      },
      created() {
          getsliders().then (res=>{
              console.log(res)
          })
      }
</script>
<script type="text/javascript"> import {getSliders} from '@/utils/api/course' export default{ data (){ return { list:[] } }, created() { getsliders().then (res=>{ console.log(res) }) } </script>

3. Ajax 原理

3.1 XMLHttpRequest

  • Ajax 是浏览器与服务器通信的技术,采用 XMLHttpRequest 对象相关代码

  • axios 是对 XHR 相关代码进行了封装,让我们只关心传递的接口参数

  • 学习 XHR 也是了解 axios 内部与服务器交互过程的真正原理

  • 语法:

const xhr = new XMLHttpRequest();
xhr.open("请求方法", "请求url网址");
xhr.addEventListener("loadend", () => {
// 响应结果
console.log(xhr.response);
});
xhr.send();
const xhr = new XMLHttpRequest();
xhr.open("请求方法", "请求url网址");
xhr.addEventListener("loadend", () => {
  // 响应结果
  console.log(xhr.response);
});
xhr.send();
const xhr = new XMLHttpRequest(); xhr.open("请求方法", "请求url网址"); xhr.addEventListener("loadend", () => { // 响应结果 console.log(xhr.response); }); xhr.send();

  • 示例 1:获取所有省份列表并展示到页面上
<p class="my-p"></p>
<script>
/**
* 目标:使用XMLHttpRequest对象与服务器通信
* 1. 创建 XMLHttpRequest 对象
* 2. 配置请求方法和请求 url 地址
* 3. 监听 loadend 事件,接收响应结果
* 4. 发起请求
*/
const xhr = new XMLHttpRequest();
xhr.open("get", "http://hmajax.itheima.net/api/province");
// 携带查询参数
// xhr.open('get', 'http://hmajax.itheima.net/api/city?pname=辽宁省')
xhr.addEventListener("loadend", () => {
// console.log(xhr.response)
const data = JSON.parse(xhr.response);
document.querySelector(".my-p").innerHTML = data.list.join("<br>");
});
xhr.send();
</script>
<p class="my-p"></p>
<script>
  /**
   * 目标:使用XMLHttpRequest对象与服务器通信
   *  1. 创建 XMLHttpRequest 对象
   *  2. 配置请求方法和请求 url 地址
   *  3. 监听 loadend 事件,接收响应结果
   *  4. 发起请求
   */
  const xhr = new XMLHttpRequest();

  xhr.open("get", "http://hmajax.itheima.net/api/province");
  // 携带查询参数
  // xhr.open('get', 'http://hmajax.itheima.net/api/city?pname=辽宁省')

  xhr.addEventListener("loadend", () => {
    // console.log(xhr.response)
    const data = JSON.parse(xhr.response);
    document.querySelector(".my-p").innerHTML = data.list.join("<br>");
  });

  xhr.send();
</script>
<p class="my-p"></p> <script> /** * 目标:使用XMLHttpRequest对象与服务器通信 * 1. 创建 XMLHttpRequest 对象 * 2. 配置请求方法和请求 url 地址 * 3. 监听 loadend 事件,接收响应结果 * 4. 发起请求 */ const xhr = new XMLHttpRequest(); xhr.open("get", "http://hmajax.itheima.net/api/province"); // 携带查询参数 // xhr.open('get', 'http://hmajax.itheima.net/api/city?pname=辽宁省') xhr.addEventListener("loadend", () => { // console.log(xhr.response) const data = JSON.parse(xhr.response); document.querySelector(".my-p").innerHTML = data.list.join("<br>"); }); xhr.send(); </script>
  • 示例 2:地区查询
<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>
/**
* 目标: 根据省份和城市名字, 查询对应的地区列表
*/
document.querySelector(".sel-btn").addEventListener("click", () => {
const pname = document.querySelector(".province").value;
const cname = document.querySelector(".city").value;
paramsObj = new URLSearchParams({
pname,
cname,
});
const xhr = new XMLHttpRequest();
xhr.open("get", `http://hmajax.itheima.net/api/area?${paramsObj}`);
xhr.addEventListener("loadend", () => {
const data = JSON.parse(xhr.response);
document.querySelector(".list-group").innerHTML = data.list
.map(areaName => {
return `<li class="list-group-item">${areaName}</li>`;
})
.join("");
});
xhr.send();
});
</script>
<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>
  /**
   * 目标: 根据省份和城市名字, 查询对应的地区列表
   */
  document.querySelector(".sel-btn").addEventListener("click", () => {
    const pname = document.querySelector(".province").value;
    const cname = document.querySelector(".city").value;

    paramsObj = new URLSearchParams({
      pname,
      cname,
    });

    const xhr = new XMLHttpRequest();
    xhr.open("get", `http://hmajax.itheima.net/api/area?${paramsObj}`);
    xhr.addEventListener("loadend", () => {
      const data = JSON.parse(xhr.response);
      document.querySelector(".list-group").innerHTML = data.list
        .map(areaName => {
          return `<li class="list-group-item">${areaName}</li>`;
        })
        .join("");
    });
    xhr.send();
  });
</script>
<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> /** * 目标: 根据省份和城市名字, 查询对应的地区列表 */ document.querySelector(".sel-btn").addEventListener("click", () => { const pname = document.querySelector(".province").value; const cname = document.querySelector(".city").value; paramsObj = new URLSearchParams({ pname, cname, }); const xhr = new XMLHttpRequest(); xhr.open("get", `http://hmajax.itheima.net/api/area?${paramsObj}`); xhr.addEventListener("loadend", () => { const data = JSON.parse(xhr.response); document.querySelector(".list-group").innerHTML = data.list .map(areaName => { return `<li class="list-group-item">${areaName}</li>`; }) .join(""); }); xhr.send(); }); </script>
  • 示例 3:数据提交
<button class="reg-btn">注册用户</button>
<script>
/**
* 目标:使用xhr进行数据提交-完成注册功能
*/
document.querySelector(".reg-btn").addEventListener("click", () => {
const xhr = new XMLHttpRequest();
xhr.open("post", "http://hmajax.itheima.net/api/register");
xhr.addEventListener("loadend", () => {
console.log(xhr.response);
});
// 设置请求头
xhr.setRequestHeader("content-type", "application/json");
// 准备提交的数据
const userObj = {
username: "itheima667",
password: "123456",
};
const userStr = JSON.stringify(userObj);
xhr.send(userStr);
});
</script>
<button class="reg-btn">注册用户</button>
<script>
  /**
   * 目标:使用xhr进行数据提交-完成注册功能
   */
  document.querySelector(".reg-btn").addEventListener("click", () => {
    const xhr = new XMLHttpRequest();

    xhr.open("post", "http://hmajax.itheima.net/api/register");

    xhr.addEventListener("loadend", () => {
      console.log(xhr.response);
    });
    // 设置请求头
    xhr.setRequestHeader("content-type", "application/json");

    // 准备提交的数据
    const userObj = {
      username: "itheima667",
      password: "123456",
    };

    const userStr = JSON.stringify(userObj);
    xhr.send(userStr);
  });
</script>
<button class="reg-btn">注册用户</button> <script> /** * 目标:使用xhr进行数据提交-完成注册功能 */ document.querySelector(".reg-btn").addEventListener("click", () => { const xhr = new XMLHttpRequest(); xhr.open("post", "http://hmajax.itheima.net/api/register"); xhr.addEventListener("loadend", () => { console.log(xhr.response); }); // 设置请求头 xhr.setRequestHeader("content-type", "application/json"); // 准备提交的数据 const userObj = { username: "itheima667", password: "123456", }; const userStr = JSON.stringify(userObj); xhr.send(userStr); }); </script>

3.2 Promise

3.2.1 对于异步的理解

  • 示例
console.log("开始"); // 立即执行,输出 "开始"
setTimeout(() => {
// 设置一个异步任务,延迟 1000 毫秒后执行
console.log("异步任务完成"); // 这个代码在 1 秒后执行
}, 1000);
console.log("结束"); // 立即执行,输出 "结束"
console.log("开始"); // 立即执行,输出 "开始"

setTimeout(() => {
  // 设置一个异步任务,延迟 1000 毫秒后执行
  console.log("异步任务完成"); // 这个代码在 1 秒后执行
}, 1000);

console.log("结束"); // 立即执行,输出 "结束"
console.log("开始"); // 立即执行,输出 "开始" setTimeout(() => { // 设置一个异步任务,延迟 1000 毫秒后执行 console.log("异步任务完成"); // 这个代码在 1 秒后执行 }, 1000); console.log("结束"); // 立即执行,输出 "结束"
  • 输出顺序

    • 开始:第一个console.log立即执行,输出"开始"

    • 结束:第二个console.log立即执行,输出"结束"

    • 异步任务完成:在设置的 1 秒之后,setTimeout中的回调函数才被调用,输出"异步任务完成"

  • 异步体现

    • 非阻塞:在setTimeout调用后,代码并没有等待 1 秒,而是继续执行后面的console.log('结束')。这说明setTimeout是非阻塞的

    • 执行顺序:即使setTimeout设置了一个 1 秒的延迟,它的回调函数并不会立即执行,而是被放入事件队列中,等待主线程空闲时再执行。这导致"结束"会在"异步任务完成"之前输出

  • 总结

    • 异步允许代码在等待某个操作(如定时器)时继续执行其他代码,而不会阻塞整个程序的执行

3.2.2 概述

  • 是什么

    • 表示(管理)一个异步操作最终状态和结果值的对象
  • Promise 的好处是什么?

    • 逻辑更清晰(成功或失败会关联后续的处理函数)

    • 了解 axios 函数内部运作的机制

    • 解决回调函数地狱问题

  • Promise 管理异步任务的语法

// 1. 创建 Promise 对象
const p = new Promise((resolve, reject) => {
// 2. 执行异步任务-并传递结果
// 成功调用: resolve(值) 触发 then() 执行
// 失败调用: reject(值) 触发 catch() 执行
});
// 3. 接收结果
p.then(result => {
// 成功
}).catch(error => {
// 失败
});
// 1. 创建 Promise 对象
const p = new Promise((resolve, reject) => {
  // 2. 执行异步任务-并传递结果
  // 成功调用: resolve(值) 触发 then() 执行
  // 失败调用: reject(值) 触发 catch() 执行
});
// 3. 接收结果
p.then(result => {
  // 成功
}).catch(error => {
  // 失败
});
// 1. 创建 Promise 对象 const p = new Promise((resolve, reject) => { // 2. 执行异步任务-并传递结果 // 成功调用: resolve(值) 触发 then() 执行 // 失败调用: reject(值) 触发 catch() 执行 }); // 3. 接收结果 p.then(result => { // 成功 }).catch(error => { // 失败 });
  • 示例
/**
* 目标:使用Promise管理异步任务
*/
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// resolve('模拟AJAX请求-成功结果')
reject(new Error("模拟AJAX请求-失败结果"));
}, 2000);
});
p.then(result => {
console.log(result);
}).catch(error => {
console.log(error);
});
/**
 * 目标:使用Promise管理异步任务
 */
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    // resolve('模拟AJAX请求-成功结果')
    reject(new Error("模拟AJAX请求-失败结果"));
  }, 2000);
});

p.then(result => {
  console.log(result);
}).catch(error => {
  console.log(error);
});
/** * 目标:使用Promise管理异步任务 */ const p = new Promise((resolve, reject) => { setTimeout(() => { // resolve('模拟AJAX请求-成功结果') reject(new Error("模拟AJAX请求-失败结果")); }, 2000); }); p.then(result => { console.log(result); }).catch(error => { console.log(error); });

3.2.3 三种状态

  • 待定(pending):初始状态,既没有被兑现,也没有被拒绝

  • 已兑现(fulfilled):操作成功完成

  • 已拒绝(rejected):操作失败

  • 改变 Promise 对象状态后,内部触发对应回调函数传参并执行

  • 注:每个 Promise 对象一旦被兑现/拒绝,那么状态无法再被改变

3.2.4 案例-获取省份列表

<p class="my-p"></p>
<script>
const p = new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open("get", "http://hmajax.itheima.net/api/province");
xhr.addEventListener("loadend", () => {
// 判断请求成功与否
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(xhr.response));
}
});
xhr.send();
});
p.then(reslut => {
document.querySelector(".my-p").innerHTML = reslut.list.join("<br>");
}).catch(error => {
// 打印详细信息
// console.dir(error)
document.querySelector(".my-p").innerHTML = error.message;
});
</script>
<p class="my-p"></p>
<script>
  const p = new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();

    xhr.open("get", "http://hmajax.itheima.net/api/province");

    xhr.addEventListener("loadend", () => {
      // 判断请求成功与否
      if (xhr.status >= 200 && xhr.status < 300) {
        resolve(JSON.parse(xhr.response));
      } else {
        reject(new Error(xhr.response));
      }
    });

    xhr.send();
  });

  p.then(reslut => {
    document.querySelector(".my-p").innerHTML = reslut.list.join("<br>");
  }).catch(error => {
    // 打印详细信息
    // console.dir(error)
    document.querySelector(".my-p").innerHTML = error.message;
  });
</script>
<p class="my-p"></p> <script> const p = new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("get", "http://hmajax.itheima.net/api/province"); xhr.addEventListener("loadend", () => { // 判断请求成功与否 if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)); } else { reject(new Error(xhr.response)); } }); xhr.send(); }); p.then(reslut => { document.querySelector(".my-p").innerHTML = reslut.list.join("<br>"); }).catch(error => { // 打印详细信息 // console.dir(error) document.querySelector(".my-p").innerHTML = error.message; }); </script>

3.2.5 封装简易 axios

  • 步骤

    • 定义 myAxios 函数,接收配置对象,返回 Promise 对象

    • 发起 XHR 请求,默认请求方法为 GET

    • 调用成功/失败的处理程序

    • 使用 myAxios 函数,获取省份列表展示

  • 核心语法

function myAxios(config) {
return new Promise((resolve, reject) => {
// XHR 请求
// 调用成功/失败的处理程序
});
}
myAxios({
url: "目标资源地址",
})
.then(result => {})
.catch(error => {});
function myAxios(config) {
  return new Promise((resolve, reject) => {
    // XHR 请求
    // 调用成功/失败的处理程序
  });
}

myAxios({
  url: "目标资源地址",
})
  .then(result => {})
  .catch(error => {});
function myAxios(config) { return new Promise((resolve, reject) => { // XHR 请求 // 调用成功/失败的处理程序 }); } myAxios({ url: "目标资源地址", }) .then(result => {}) .catch(error => {});
  • 示例:获取省份列表
<p class="my-p"></p>
<script>
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open(config.method || "get", config.url);
xhr.addEventListener("loadend", () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(xhr.response));
}
});
xhr.send();
});
}
myAxios({
url: "http://hmajax.itheima.net/api/province",
})
.then(result => {
document.querySelector(".my-p").innerHTML = result.list.join("<br>");
})
.catch(error => {
document.querySelector(".my-p").innerHTML = error.message;
});
</script>
<p class="my-p"></p>
<script>
  function myAxios(config) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();

      xhr.open(config.method || "get", config.url);

      xhr.addEventListener("loadend", () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(JSON.parse(xhr.response));
        } else {
          reject(new Error(xhr.response));
        }
      });

      xhr.send();
    });
  }

  myAxios({
    url: "http://hmajax.itheima.net/api/province",
  })
    .then(result => {
      document.querySelector(".my-p").innerHTML = result.list.join("<br>");
    })
    .catch(error => {
      document.querySelector(".my-p").innerHTML = error.message;
    });
</script>
<p class="my-p"></p> <script> function myAxios(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open(config.method || "get", config.url); xhr.addEventListener("loadend", () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)); } else { reject(new Error(xhr.response)); } }); xhr.send(); }); } myAxios({ url: "http://hmajax.itheima.net/api/province", }) .then(result => { document.querySelector(".my-p").innerHTML = result.list.join("<br>"); }) .catch(error => { document.querySelector(".my-p").innerHTML = error.message; }); </script>
  • 示例:获取地区列表
<p class="my-p"></p>
<script>
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// 查询参数
if (config.params) {
const paramsObj = new URLSearchParams(config.params);
const paramsStr = paramsObj.toString();
config.url += `?${paramsStr}`;
}
xhr.open(config.method || "get", config.url);
xhr.addEventListener("loadend", () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(xhr.response));
}
});
xhr.send();
});
}
myAxios({
url: "http://hmajax.itheima.net/api/area",
params: {
pname: "辽宁省",
cname: "大连市",
},
})
.then(result => {
document.querySelector(".my-p").innerHTML = result.list.join("<br>");
})
.catch(error => {
document.querySelector(".my-p").innerHTML = error.message;
});
</script>
<p class="my-p"></p>
<script>
  function myAxios(config) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      // 查询参数
      if (config.params) {
        const paramsObj = new URLSearchParams(config.params);
        const paramsStr = paramsObj.toString();
        config.url += `?${paramsStr}`;
      }

      xhr.open(config.method || "get", config.url);

      xhr.addEventListener("loadend", () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(JSON.parse(xhr.response));
        } else {
          reject(new Error(xhr.response));
        }
      });

      xhr.send();
    });
  }

  myAxios({
    url: "http://hmajax.itheima.net/api/area",
    params: {
      pname: "辽宁省",
      cname: "大连市",
    },
  })
    .then(result => {
      document.querySelector(".my-p").innerHTML = result.list.join("<br>");
    })
    .catch(error => {
      document.querySelector(".my-p").innerHTML = error.message;
    });
</script>
<p class="my-p"></p> <script> function myAxios(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); // 查询参数 if (config.params) { const paramsObj = new URLSearchParams(config.params); const paramsStr = paramsObj.toString(); config.url += `?${paramsStr}`; } xhr.open(config.method || "get", config.url); xhr.addEventListener("loadend", () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)); } else { reject(new Error(xhr.response)); } }); xhr.send(); }); } myAxios({ url: "http://hmajax.itheima.net/api/area", params: { pname: "辽宁省", cname: "大连市", }, }) .then(result => { document.querySelector(".my-p").innerHTML = result.list.join("<br>"); }) .catch(error => { document.querySelector(".my-p").innerHTML = error.message; }); </script>
  • 示例:注册用户
<p class="my-p"></p>
<script>
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// 查询参数
if (config.params) {
const paramsObj = new URLSearchParams(config.params);
const paramsStr = paramsObj.toString();
config.url += `?${paramsStr}`;
}
xhr.open(config.method || "get", config.url);
xhr.addEventListener("loadend", () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(xhr.response));
}
});
if (config.data) {
xhr.setRequestHeader("content-type", "application/json");
const jsonStr = JSON.stringify(config.data);
xhr.send(jsonStr);
} else {
xhr.send();
}
});
}
myAxios({
url: "http://hmajax.itheima.net/api/register",
method: "post",
data: {
username: "itheima776",
password: "66688879",
},
})
.then(result => {
document.querySelector(".my-p").innerHTML = result.message;
})
.catch(error => {
document.querySelector(".my-p").innerHTML = error.message;
});
</script>
<p class="my-p"></p>
<script>
  function myAxios(config) {
    return new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      // 查询参数
      if (config.params) {
        const paramsObj = new URLSearchParams(config.params);
        const paramsStr = paramsObj.toString();
        config.url += `?${paramsStr}`;
      }

      xhr.open(config.method || "get", config.url);

      xhr.addEventListener("loadend", () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          resolve(JSON.parse(xhr.response));
        } else {
          reject(new Error(xhr.response));
        }
      });

      if (config.data) {
        xhr.setRequestHeader("content-type", "application/json");
        const jsonStr = JSON.stringify(config.data);
        xhr.send(jsonStr);
      } else {
        xhr.send();
      }
    });
  }

  myAxios({
    url: "http://hmajax.itheima.net/api/register",
    method: "post",
    data: {
      username: "itheima776",
      password: "66688879",
    },
  })
    .then(result => {
      document.querySelector(".my-p").innerHTML = result.message;
    })
    .catch(error => {
      document.querySelector(".my-p").innerHTML = error.message;
    });
</script>
<p class="my-p"></p> <script> function myAxios(config) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); // 查询参数 if (config.params) { const paramsObj = new URLSearchParams(config.params); const paramsStr = paramsObj.toString(); config.url += `?${paramsStr}`; } xhr.open(config.method || "get", config.url); xhr.addEventListener("loadend", () => { if (xhr.status >= 200 && xhr.status < 300) { resolve(JSON.parse(xhr.response)); } else { reject(new Error(xhr.response)); } }); if (config.data) { xhr.setRequestHeader("content-type", "application/json"); const jsonStr = JSON.stringify(config.data); xhr.send(jsonStr); } else { xhr.send(); } }); } myAxios({ url: "http://hmajax.itheima.net/api/register", method: "post", data: { username: "itheima776", password: "66688879", }, }) .then(result => { document.querySelector(".my-p").innerHTML = result.message; }) .catch(error => { document.querySelector(".my-p").innerHTML = error.message; }); </script>

3.2.6 回调函数地狱

  • 概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱

  • 缺点:可读性差,异常无法捕获,耦合性严重,牵一发动全身

<form>
<span>省份:</span>
<select>
<option class="province"></option>
</select>
<span>城市:</span>
<select>
<option class="city"></option>
</select>
<span>地区:</span>
<select>
<option class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/**
* 目标:演示回调函数地狱
* 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
*/
axios({ url: "http://hmajax.itheima.net/api/province" })
.then(result => {
const pname = result.data.list[0];
document.querySelector(".province").innerHTML = pname;
axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } }).then(result => {
const cname = result.data.list[0];
document.querySelector(".city").innerHTML = cname;
axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } }).then(result => {
const aname = result.data.list[0];
document.querySelector(".area").innerHTML = aname;
});
});
})
.catch(error => {
console.log(error);
});
</script>
<form>
  <span>省份:</span>
  <select>
    <option class="province"></option>
  </select>
  <span>城市:</span>
  <select>
    <option class="city"></option>
  </select>
  <span>地区:</span>
  <select>
    <option class="area"></option>
  </select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  /**
   * 目标:演示回调函数地狱
   * 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
   */
  axios({ url: "http://hmajax.itheima.net/api/province" })
    .then(result => {
      const pname = result.data.list[0];
      document.querySelector(".province").innerHTML = pname;
      axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } }).then(result => {
        const cname = result.data.list[0];
        document.querySelector(".city").innerHTML = cname;
        axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } }).then(result => {
          const aname = result.data.list[0];
          document.querySelector(".area").innerHTML = aname;
        });
      });
    })
    .catch(error => {
      console.log(error);
    });
</script>
<form> <span>省份:</span> <select> <option class="province"></option> </select> <span>城市:</span> <select> <option class="city"></option> </select> <span>地区:</span> <select> <option class="area"></option> </select> </form> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /** * 目标:演示回调函数地狱 * 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中 */ axios({ url: "http://hmajax.itheima.net/api/province" }) .then(result => { const pname = result.data.list[0]; document.querySelector(".province").innerHTML = pname; axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } }).then(result => { const cname = result.data.list[0]; document.querySelector(".city").innerHTML = cname; axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } }).then(result => { const aname = result.data.list[0]; document.querySelector(".area").innerHTML = aname; }); }); }) .catch(error => { console.log(error); }); </script>

3.2.7 Promise 链式调用

  • 概念:依靠 then() 方法会返回一个新生成的 Promise 对象特性,继续串联下一环任务,直到结束

  • 细节:then() 回调函数中的返回值,会影响新生成的 Promise 对象最终状态和结果

  • 好处:通过链式调用,解决回调函数嵌套问题

const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("北京市");
}, 1000);
});
const p2 = p.then(result => {
console.log(result);
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`${result} --- 北京`);
}, 1000);
});
});
p2.then(result => {
console.log(result);
});
const p = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("北京市");
  }, 1000);
});

const p2 = p.then(result => {
  console.log(result);
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(`${result} --- 北京`);
    }, 1000);
  });
});

p2.then(result => {
  console.log(result);
});
const p = new Promise((resolve, reject) => { setTimeout(() => { resolve("北京市"); }, 1000); }); const p2 = p.then(result => { console.log(result); return new Promise((resolve, reject) => { setTimeout(() => { resolve(`${result} --- 北京`); }, 1000); }); }); p2.then(result => { console.log(result); });
  • 解决回调函数地狱
<form>
<span>省份:</span>
<select>
<option class="province"></option>
</select>
<span>城市:</span>
<select>
<option class="city"></option>
</select>
<span>地区:</span>
<select>
<option class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
let pname = "";
axios({ url: "http://hmajax.itheima.net/api/province" })
.then(result => {
pname = result.data.list[0];
document.querySelector(".province").innerHTML = pname;
return axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } });
})
.then(result => {
const cname = result.data.list[0];
document.querySelector(".city").innerHTML = cname;
return axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } });
})
.then(result => {
const aname = result.data.list[0];
document.querySelector(".area").innerHTML = aname;
});
</script>
<form>
  <span>省份:</span>
  <select>
    <option class="province"></option>
  </select>
  <span>城市:</span>
  <select>
    <option class="city"></option>
  </select>
  <span>地区:</span>
  <select>
    <option class="area"></option>
  </select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  let pname = "";
  axios({ url: "http://hmajax.itheima.net/api/province" })
    .then(result => {
      pname = result.data.list[0];
      document.querySelector(".province").innerHTML = pname;
      return axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } });
    })
    .then(result => {
      const cname = result.data.list[0];
      document.querySelector(".city").innerHTML = cname;
      return axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } });
    })
    .then(result => {
      const aname = result.data.list[0];
      document.querySelector(".area").innerHTML = aname;
    });
</script>
<form> <span>省份:</span> <select> <option class="province"></option> </select> <span>城市:</span> <select> <option class="city"></option> </select> <span>地区:</span> <select> <option class="area"></option> </select> </form> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> let pname = ""; axios({ url: "http://hmajax.itheima.net/api/province" }) .then(result => { pname = result.data.list[0]; document.querySelector(".province").innerHTML = pname; return axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } }); }) .then(result => { const cname = result.data.list[0]; document.querySelector(".city").innerHTML = cname; return axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } }); }) .then(result => { const aname = result.data.list[0]; document.querySelector(".area").innerHTML = aname; }); </script>

3.2.8 async 函数和 await

在 async 函数内,使用 await 关键字取代 then 函数,等待获取 Promise 对象成功状态的结果值

<form>
<span>省份:</span>
<select>
<option class="province"></option>
</select>
<span>城市:</span>
<select>
<option class="city"></option>
</select>
<span>地区:</span>
<select>
<option class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
async function getData() {
const pObj = await axios({ url: "http://hmajax.itheima.net/api/province" });
const pname = pObj.data.list[0];
const cObj = await axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } });
const cname = cObj.data.list[0];
const aObj = await axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } });
const aname = aObj.data.list[0];
document.querySelector(".province").innerHTML = pname;
document.querySelector(".city").innerHTML = cname;
document.querySelector(".area").innerHTML = aname;
}
getData();
</script>
<form>
  <span>省份:</span>
  <select>
    <option class="province"></option>
  </select>
  <span>城市:</span>
  <select>
    <option class="city"></option>
  </select>
  <span>地区:</span>
  <select>
    <option class="area"></option>
  </select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  async function getData() {
    const pObj = await axios({ url: "http://hmajax.itheima.net/api/province" });
    const pname = pObj.data.list[0];
    const cObj = await axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } });
    const cname = cObj.data.list[0];
    const aObj = await axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } });
    const aname = aObj.data.list[0];

    document.querySelector(".province").innerHTML = pname;
    document.querySelector(".city").innerHTML = cname;
    document.querySelector(".area").innerHTML = aname;
  }
  getData();
</script>
<form> <span>省份:</span> <select> <option class="province"></option> </select> <span>城市:</span> <select> <option class="city"></option> </select> <span>地区:</span> <select> <option class="area"></option> </select> </form> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> async function getData() { const pObj = await axios({ url: "http://hmajax.itheima.net/api/province" }); const pname = pObj.data.list[0]; const cObj = await axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } }); const cname = cObj.data.list[0]; const aObj = await axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } }); const aname = aObj.data.list[0]; document.querySelector(".province").innerHTML = pname; document.querySelector(".city").innerHTML = cname; document.querySelector(".area").innerHTML = aname; } getData(); </script>
  • 捕获错误
try {
// 要执行的代码
// 如果try里某行代码报错后,try中剩余的代码不会执行了
} catch (error) {
// error 接收的是
错误消息;
// try 里代码,如果有错误,直接进入这里执行
}
try {
  // 要执行的代码
  // 如果try里某行代码报错后,try中剩余的代码不会执行了
} catch (error) {
  // error 接收的是
  错误消息;
  // try 里代码,如果有错误,直接进入这里执行
}
try { // 要执行的代码 // 如果try里某行代码报错后,try中剩余的代码不会执行了 } catch (error) { // error 接收的是 错误消息; // try 里代码,如果有错误,直接进入这里执行 }
  • 示例
<form>
<span>省份:</span>
<select>
<option class="province"></option>
</select>
<span>城市:</span>
<select>
<option class="city"></option>
</select>
<span>地区:</span>
<select>
<option class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
async function getData() {
try {
const pObj = await axios({ url: "http://hmajax.itheima.net/api/province" });
const pname = pObj.data.list[0];
const cObj = await axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } });
const cname = cObj.data.list[0];
const aObj = await axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } });
const aname = aObj.data.list[0];
document.querySelector(".province").innerHTML = pname;
document.querySelector(".city").innerHTML = cname;
document.querySelector(".area").innerHTML = aname;
} catch (error) {
console.dir(error);
}
}
getData();
</script>
<form>
  <span>省份:</span>
  <select>
    <option class="province"></option>
  </select>
  <span>城市:</span>
  <select>
    <option class="city"></option>
  </select>
  <span>地区:</span>
  <select>
    <option class="area"></option>
  </select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  async function getData() {
    try {
      const pObj = await axios({ url: "http://hmajax.itheima.net/api/province" });
      const pname = pObj.data.list[0];
      const cObj = await axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } });
      const cname = cObj.data.list[0];
      const aObj = await axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } });
      const aname = aObj.data.list[0];

      document.querySelector(".province").innerHTML = pname;
      document.querySelector(".city").innerHTML = cname;
      document.querySelector(".area").innerHTML = aname;
    } catch (error) {
      console.dir(error);
    }
  }
  getData();
</script>
<form> <span>省份:</span> <select> <option class="province"></option> </select> <span>城市:</span> <select> <option class="city"></option> </select> <span>地区:</span> <select> <option class="area"></option> </select> </form> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> async function getData() { try { const pObj = await axios({ url: "http://hmajax.itheima.net/api/province" }); const pname = pObj.data.list[0]; const cObj = await axios({ url: "http://hmajax.itheima.net/api/city", params: { pname } }); const cname = cObj.data.list[0]; const aObj = await axios({ url: "http://hmajax.itheima.net/api/area", params: { pname, cname } }); const aname = aObj.data.list[0]; document.querySelector(".province").innerHTML = pname; document.querySelector(".city").innerHTML = cname; document.querySelector(".area").innerHTML = aname; } catch (error) { console.dir(error); } } getData(); </script>

3.3 事件循环(EventLoop)

  • 作用:事件循环负责执行代码,收集和处理事件以及执行队列中的子任务

  • 原因:JavaScript 单线程(某一刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环模型

  • 概念:执行代码和收集异步任务的模型,在调用栈空闲时,反复调用任务队列里回调函数的执行机制

  • JavaScript 内代码如何执行?

    • 执行同步代码,遇到异步代码交给宿主浏览器环境执行,异步有了结果后,把回调函数放入任务队列排队当调用栈空闲后,反复调用任务队列里的回调函数
  • 练习

/**
* 目标:阅读并回答执行的顺序结果
*/
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
function myFn() {
console.log(3);
}
function ajaxFn() {
const xhr = new XMLHttpRequest();
xhr.open("GET", "http://hmajax.itheima.net/api/province");
xhr.addEventListener("loadend", () => {
console.log(4);
});
xhr.send();
}
for (let i = 0; i < 1; i++) {
console.log(5);
}
ajaxFn();
document.addEventListener("click", () => {
console.log(6);
});
myFn();
/**
 * 目标:阅读并回答执行的顺序结果
 */
console.log(1);
setTimeout(() => {
  console.log(2);
}, 0);
function myFn() {
  console.log(3);
}
function ajaxFn() {
  const xhr = new XMLHttpRequest();
  xhr.open("GET", "http://hmajax.itheima.net/api/province");
  xhr.addEventListener("loadend", () => {
    console.log(4);
  });
  xhr.send();
}
for (let i = 0; i < 1; i++) {
  console.log(5);
}
ajaxFn();
document.addEventListener("click", () => {
  console.log(6);
});
myFn();
/** * 目标:阅读并回答执行的顺序结果 */ console.log(1); setTimeout(() => { console.log(2); }, 0); function myFn() { console.log(3); } function ajaxFn() { const xhr = new XMLHttpRequest(); xhr.open("GET", "http://hmajax.itheima.net/api/province"); xhr.addEventListener("loadend", () => { console.log(4); }); xhr.send(); } for (let i = 0; i < 1; i++) { console.log(5); } ajaxFn(); document.addEventListener("click", () => { console.log(6); }); myFn();

结果:1 5 3 2 4 点击一次 document 就会执行一次打印 6

3.4 宏任务与微任务

  • 异步任务分为

    • 宏任务:由浏览器环境执行的异步代码

    • 微任务:由 JS 引擎环境执行的异步代码

  • 事件循环模型
console.log(1);
setTimeout(() => {
console.log(2);
}, 0);
const p = new Promise((resolve, reject) => {
resolve(3);
});
p.then(res => {
console.log(res);
});
console.log(4);
console.log(1);
setTimeout(() => {
  console.log(2);
}, 0);
const p = new Promise((resolve, reject) => {
  resolve(3);
});
p.then(res => {
  console.log(res);
});
console.log(4);
console.log(1); setTimeout(() => { console.log(2); }, 0); const p = new Promise((resolve, reject) => { resolve(3); }); p.then(res => { console.log(res); }); console.log(4);

  • 注:宏任务每次在执行同步代码时,产生微任务队列,清空微任务队列任务后,微任务队列空间释放!下一次宏任务执行时,遇到微任务代码,才会再次申请微任务队列空间放入回调函数消息排队

  • 总结:一个宏任务包含微任务队列,他们之间是包含关系,不是并列关系

  • 经典面试题

// 目标:回答代码执行顺序
console.log(1);
setTimeout(() => {
console.log(2);
const p = new Promise(resolve => resolve(3));
p.then(result => console.log(result));
}, 0);
const p = new Promise(resolve => {
setTimeout(() => {
console.log(4);
}, 0);
resolve(5);
});
p.then(result => console.log(result));
const p2 = new Promise(resolve => resolve(6));
p2.then(result => console.log(result));
console.log(7);
// 目标:回答代码执行顺序
console.log(1);
setTimeout(() => {
  console.log(2);
  const p = new Promise(resolve => resolve(3));
  p.then(result => console.log(result));
}, 0);
const p = new Promise(resolve => {
  setTimeout(() => {
    console.log(4);
  }, 0);
  resolve(5);
});
p.then(result => console.log(result));
const p2 = new Promise(resolve => resolve(6));
p2.then(result => console.log(result));
console.log(7);
// 目标:回答代码执行顺序 console.log(1); setTimeout(() => { console.log(2); const p = new Promise(resolve => resolve(3)); p.then(result => console.log(result)); }, 0); const p = new Promise(resolve => { setTimeout(() => { console.log(4); }, 0); resolve(5); }); p.then(result => console.log(result)); const p2 = new Promise(resolve => resolve(6)); p2.then(result => console.log(result)); console.log(7);

结果:1 7 5 6 2 3 4

3.5 Promise.all 静态方法

  • 作用:合并多个 Promise 对象,等待所有同时成功完成(或某一个失败),做后续逻辑

  • 语法:
const p = Promise.all([Promise对象, Promise对象, ...]) // 需要传入一个可迭代的数据
p.then(result => {
// result 结果: [Promise对象成功结果, Promise对象成功结果, ...]
}).catch(error => {
// 第一个失败的 Promise 对象,抛出的异常对象
})
const p = Promise.all([Promise对象, Promise对象, ...])  // 需要传入一个可迭代的数据
p.then(result => {
  // result 结果: [Promise对象成功结果, Promise对象成功结果, ...]
}).catch(error => {
  // 第一个失败的 Promise 对象,抛出的异常对象
})
const p = Promise.all([Promise对象, Promise对象, ...]) // 需要传入一个可迭代的数据 p.then(result => { // result 结果: [Promise对象成功结果, Promise对象成功结果, ...] }).catch(error => { // 第一个失败的 Promise 对象,抛出的异常对象 })
  • 示例:同时请求“北京”,“上海”,“广州”,“深圳”的天气并在网页尽可能同时显示
<ul class="my-ul"></ul>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/**
* 业务:当我需要同一时间显示多个请求的结果时,就要把多请求合并
* 例如:默认显示"北京", "上海", "广州", "深圳"的天气在首页查看
* code:
* 北京-110100
* 上海-310100
* 广州-440100
* 深圳-440300
*/
// 1. 请求城市天气,得到Promise对象(此处可以使用数组遍历)
const bjPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "110100" } });
const shPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "310100" } });
const gzPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "440100" } });
const szPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "440300" } });
// 2. 使用Promise.all,合并多个Promise对象
const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise]);
p.then(result => {
// 注意:结果数组顺序和合并时顺序是一致
console.log(result);
const htmlStr = result
.map(item => {
return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>`;
})
.join("");
document.querySelector(".my-ul").innerHTML = htmlStr;
}).catch(error => {
console.dir(error);
});
</script>
<ul class="my-ul"></ul>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  /**
   * 业务:当我需要同一时间显示多个请求的结果时,就要把多请求合并
   * 例如:默认显示"北京", "上海", "广州", "深圳"的天气在首页查看
   * code:
   * 北京-110100
   * 上海-310100
   * 广州-440100
   * 深圳-440300
   */
  // 1. 请求城市天气,得到Promise对象(此处可以使用数组遍历)
  const bjPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "110100" } });
  const shPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "310100" } });
  const gzPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "440100" } });
  const szPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "440300" } });

  // 2. 使用Promise.all,合并多个Promise对象
  const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise]);
  p.then(result => {
    // 注意:结果数组顺序和合并时顺序是一致
    console.log(result);
    const htmlStr = result
      .map(item => {
        return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>`;
      })
      .join("");
    document.querySelector(".my-ul").innerHTML = htmlStr;
  }).catch(error => {
    console.dir(error);
  });
</script>
<ul class="my-ul"></ul> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> /** * 业务:当我需要同一时间显示多个请求的结果时,就要把多请求合并 * 例如:默认显示"北京", "上海", "广州", "深圳"的天气在首页查看 * code: * 北京-110100 * 上海-310100 * 广州-440100 * 深圳-440300 */ // 1. 请求城市天气,得到Promise对象(此处可以使用数组遍历) const bjPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "110100" } }); const shPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "310100" } }); const gzPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "440100" } }); const szPromise = axios({ url: "http://hmajax.itheima.net/api/weather", params: { city: "440300" } }); // 2. 使用Promise.all,合并多个Promise对象 const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise]); p.then(result => { // 注意:结果数组顺序和合并时顺序是一致 console.log(result); const htmlStr = result .map(item => { return `<li>${item.data.data.area} --- ${item.data.data.weather}</li>`; }) .join(""); document.querySelector(".my-ul").innerHTML = htmlStr; }).catch(error => { console.dir(error); }); </script>
  • 案例:商品分类

    • 目标:把所有商品分类“同时”渲染到页面上

    • 获取所有一级分类数据

    • 遍历 id,创建获取二级分类请求

    • 合并所有二级分类 Promise 对象

    • 等待同时成功后,渲染页面

<!-- 大容器 -->
<div class="container">
<div class="sub-list"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
// 1. 获取所有一级分类数据
axios({
url: "http://hmajax.itheima.net/api/category/top",
}).then(result => {
// console.log(result)
const secPromiseList = result.data.data.map(item => {
// 2. 遍历id,创建获取二级分类请求
return axios({
url: "http://hmajax.itheima.net/api/category/sub",
params: {
id: item.id,
},
});
});
const p = Promise.all(secPromiseList);
p.then(result => {
// console.log(result)
document.querySelector(".sub-list").innerHTML = result
.map(item => {
const dataObj = item.data.data;
return `
<div class="item">
<h3>${dataObj.name}</h3>
<ul>
${dataObj.children
.map(item => {
return `
<li>
<a href="javascript:;">
<img src="${item.picture}" />
<p>${item.name}</p>
</a>
</li>
`;
})
.join("")}
</ul>
</div>
`;
})
.join("");
});
});
</script>
<!-- 大容器 -->
<div class="container">
  <div class="sub-list"></div>
</div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
  // 1. 获取所有一级分类数据
  axios({
    url: "http://hmajax.itheima.net/api/category/top",
  }).then(result => {
    // console.log(result)
    const secPromiseList = result.data.data.map(item => {
      // 2. 遍历id,创建获取二级分类请求
      return axios({
        url: "http://hmajax.itheima.net/api/category/sub",
        params: {
          id: item.id,
        },
      });
    });
    const p = Promise.all(secPromiseList);
    p.then(result => {
      // console.log(result)
      document.querySelector(".sub-list").innerHTML = result
        .map(item => {
          const dataObj = item.data.data;
          return `
          <div class="item">
            <h3>${dataObj.name}</h3>
            <ul>
              ${dataObj.children
                .map(item => {
                  return `
                    <li>
                      <a href="javascript:;">
                        <img src="${item.picture}" />
                        <p>${item.name}</p>
              </a>
            </li>
                    `;
                })
                .join("")}
        </ul>
         </div>
          `;
        })
        .join("");
    });
  });
</script>
<!-- 大容器 --> <div class="container"> <div class="sub-list"></div> </div> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> <script> // 1. 获取所有一级分类数据 axios({ url: "http://hmajax.itheima.net/api/category/top", }).then(result => { // console.log(result) const secPromiseList = result.data.data.map(item => { // 2. 遍历id,创建获取二级分类请求 return axios({ url: "http://hmajax.itheima.net/api/category/sub", params: { id: item.id, }, }); }); const p = Promise.all(secPromiseList); p.then(result => { // console.log(result) document.querySelector(".sub-list").innerHTML = result .map(item => { const dataObj = item.data.data; return ` <div class="item"> <h3>${dataObj.name}</h3> <ul> ${dataObj.children .map(item => { return ` <li> <a href="javascript:;"> <img src="${item.picture}" /> <p>${item.name}</p> </a> </li> `; }) .join("")} </ul> </div> `; }) .join(""); }); }); </script>
  • 案例:学习反馈

  • 框架

<div class="container">
<h4 class="stu-title">学习反馈</h4>
<img class="bg" src="./img/head.png" />
<div class="item-wrap">
<div class="hot-area">
<span class="hot">热门校区</span>
<ul class="nav">
<li><a target="_blank" href="http://bjcp.itheima.com/">北京</a></li>
<li><a target="_blank" href="http://sh.itheima.com/">上海</a></li>
<li><a target="_blank" href="http://gz.itheima.com/">广州</a></li>
<li><a target="_blank" href="http://sz.itheima.com/">深圳</a></li>
</ul>
</div>
<form class="info-form">
<div class="area-box">
<span class="title">地区选择</span>
<select name="province" class="province">
<option value="">省份</option>
</select>
<select name="city" class="city">
<option value="">城市</option>
</select>
<select name="area" class="area">
<option value="">地区</option>
</select>
</div>
<div class="area-box">
<span class="title">您的称呼</span>
<input type="text" name="nickname" class="nickname" value="播仔" />
</div>
<div class="area-box">
<span class="title">宝贵建议</span>
<textarea type="text" name="feedback" class="feedback" placeholder="您对AJAX阶段课程宝贵的建议"></textarea>
</div>
<div class="area-box">
<button type="button" class="btn btn-secondary submit">确定提交</button>
</div>
</form>
</div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script>
<script src="./js/form-serialize.js"></script>
<!-- 核心代码 -->
<script src="./js/index.js"></script>
<div class="container">
  <h4 class="stu-title">学习反馈</h4>
  <img class="bg" src="./img/head.png"  />
  <div class="item-wrap">
    <div class="hot-area">
      <span class="hot">热门校区</span>
      <ul class="nav">
        <li><a target="_blank" href="http://bjcp.itheima.com/">北京</a></li>
        <li><a target="_blank" href="http://sh.itheima.com/">上海</a></li>
        <li><a target="_blank" href="http://gz.itheima.com/">广州</a></li>
        <li><a target="_blank" href="http://sz.itheima.com/">深圳</a></li>
      </ul>
    </div>
    <form class="info-form">
      <div class="area-box">
        <span class="title">地区选择</span>
        <select name="province" class="province">
          <option value="">省份</option>
        </select>
        <select name="city" class="city">
          <option value="">城市</option>
        </select>
        <select name="area" class="area">
          <option value="">地区</option>
        </select>
      </div>
      <div class="area-box">
        <span class="title">您的称呼</span>
        <input type="text" name="nickname" class="nickname" value="播仔" />
      </div>
      <div class="area-box">
        <span class="title">宝贵建议</span>
        <textarea type="text" name="feedback" class="feedback" placeholder="您对AJAX阶段课程宝贵的建议"></textarea>
      </div>
      <div class="area-box">
        <button type="button" class="btn btn-secondary submit">确定提交</button>
      </div>
    </form>
  </div>
</div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script>
<script src="./js/form-serialize.js"></script>
<!-- 核心代码 -->
<script src="./js/index.js"></script>
<div class="container"> <h4 class="stu-title">学习反馈</h4> <img class="bg" src="./img/head.png" /> <div class="item-wrap"> <div class="hot-area"> <span class="hot">热门校区</span> <ul class="nav"> <li><a target="_blank" href="http://bjcp.itheima.com/">北京</a></li> <li><a target="_blank" href="http://sh.itheima.com/">上海</a></li> <li><a target="_blank" href="http://gz.itheima.com/">广州</a></li> <li><a target="_blank" href="http://sz.itheima.com/">深圳</a></li> </ul> </div> <form class="info-form"> <div class="area-box"> <span class="title">地区选择</span> <select name="province" class="province"> <option value="">省份</option> </select> <select name="city" class="city"> <option value="">城市</option> </select> <select name="area" class="area"> <option value="">地区</option> </select> </div> <div class="area-box"> <span class="title">您的称呼</span> <input type="text" name="nickname" class="nickname" value="播仔" /> </div> <div class="area-box"> <span class="title">宝贵建议</span> <textarea type="text" name="feedback" class="feedback" placeholder="您对AJAX阶段课程宝贵的建议"></textarea> </div> <div class="area-box"> <button type="button" class="btn btn-secondary submit">确定提交</button> </div> </form> </div> </div> <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.2.0/axios.min.js"></script> <script src="./js/form-serialize.js"></script> <!-- 核心代码 --> <script src="./js/index.js"></script>
  • index.js
/**
* 目标1:完成省市区下拉列表切换
* 1.1 设置省份下拉菜单数据
* 1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
* 1.3 切换城市,设置地区下拉菜单数据
*/
// 1.1 设置省份下拉菜单数据
axios({
url: "http://hmajax.itheima.net/api/province",
}).then(result => {
const str = result.data.list.map(pname => `<option value="${pname}">${pname}</option>`).join("");
document.querySelector(".province").innerHTML = `<option value="">省份</option>` + str;
});
// 1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
document.querySelector(".province").addEventListener("change", async e => {
const result = await axios({
url: "http://hmajax.itheima.net/api/city",
params: {
pname: e.target.value,
},
});
// console.log(result)
const str = result.data.list
.map(cname => {
return `<option value="${cname}">${cname}</option>`;
})
.join("");
document.querySelector(".city").innerHTML = `<option value="">城市</option>` + str;
// 清空地区下拉菜单
document.querySelector(".area").innerHTML = `<option value="">地区</option>`;
});
// 1.3 切换城市,设置地区下拉菜单数据
document.querySelector(".city").addEventListener("change", async e => {
const result = await axios({
url: "http://hmajax.itheima.net/api/area",
params: {
pname: document.querySelector(".province").value,
cname: e.target.value,
},
});
const str = result.data.list.map(aname => `<option value="${aname}">${aname}</option>`);
document.querySelector(".area").innerHTML = `<option value="">地区</option>` + str;
});
/**
* 目标2:收集数据提交保存
* 2.1监听提交的点击事件
* 2.2依靠插件收集表单数据
* 2.3基于axios提交保存,显示结果
*/
document.querySelector(".submit").addEventListener("click", async () => {
try {
const form = document.querySelector(".info-form");
const data = serialize(form, { hash: true, empty: true });
const result = await axios({
url: "http://hmajax.itheima.net/api/feedback",
method: "post",
data,
});
alert(result.data.message);
} catch (error) {
// console.dir(error)
alert(error.response.data.message);
}
});
/**
 * 目标1:完成省市区下拉列表切换
 *  1.1 设置省份下拉菜单数据
 *  1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
 *  1.3 切换城市,设置地区下拉菜单数据
 */
// 1.1 设置省份下拉菜单数据
axios({
  url: "http://hmajax.itheima.net/api/province",
}).then(result => {
  const str = result.data.list.map(pname => `<option value="${pname}">${pname}</option>`).join("");
  document.querySelector(".province").innerHTML = `<option value="">省份</option>` + str;
});

// 1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单
document.querySelector(".province").addEventListener("change", async e => {
  const result = await axios({
    url: "http://hmajax.itheima.net/api/city",
    params: {
      pname: e.target.value,
    },
  });
  // console.log(result)
  const str = result.data.list
    .map(cname => {
      return `<option value="${cname}">${cname}</option>`;
    })
    .join("");

  document.querySelector(".city").innerHTML = `<option value="">城市</option>` + str;

  // 清空地区下拉菜单
  document.querySelector(".area").innerHTML = `<option value="">地区</option>`;
});

// 1.3 切换城市,设置地区下拉菜单数据
document.querySelector(".city").addEventListener("change", async e => {
  const result = await axios({
    url: "http://hmajax.itheima.net/api/area",
    params: {
      pname: document.querySelector(".province").value,
      cname: e.target.value,
    },
  });
  const str = result.data.list.map(aname => `<option value="${aname}">${aname}</option>`);
  document.querySelector(".area").innerHTML = `<option value="">地区</option>` + str;
});
/**
 * 目标2:收集数据提交保存
 *  2.1监听提交的点击事件
 *  2.2依靠插件收集表单数据
 *  2.3基于axios提交保存,显示结果
 */

document.querySelector(".submit").addEventListener("click", async () => {
  try {
    const form = document.querySelector(".info-form");
    const data = serialize(form, { hash: true, empty: true });
    const result = await axios({
      url: "http://hmajax.itheima.net/api/feedback",
      method: "post",
      data,
    });
    alert(result.data.message);
  } catch (error) {
    // console.dir(error)
    alert(error.response.data.message);
  }
});
/** * 目标1:完成省市区下拉列表切换 * 1.1 设置省份下拉菜单数据 * 1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单 * 1.3 切换城市,设置地区下拉菜单数据 */ // 1.1 设置省份下拉菜单数据 axios({ url: "http://hmajax.itheima.net/api/province", }).then(result => { const str = result.data.list.map(pname => `<option value="${pname}">${pname}</option>`).join(""); document.querySelector(".province").innerHTML = `<option value="">省份</option>` + str; }); // 1.2 切换省份,设置城市下拉菜单数据,清空地区下拉菜单 document.querySelector(".province").addEventListener("change", async e => { const result = await axios({ url: "http://hmajax.itheima.net/api/city", params: { pname: e.target.value, }, }); // console.log(result) const str = result.data.list .map(cname => { return `<option value="${cname}">${cname}</option>`; }) .join(""); document.querySelector(".city").innerHTML = `<option value="">城市</option>` + str; // 清空地区下拉菜单 document.querySelector(".area").innerHTML = `<option value="">地区</option>`; }); // 1.3 切换城市,设置地区下拉菜单数据 document.querySelector(".city").addEventListener("change", async e => { const result = await axios({ url: "http://hmajax.itheima.net/api/area", params: { pname: document.querySelector(".province").value, cname: e.target.value, }, }); const str = result.data.list.map(aname => `<option value="${aname}">${aname}</option>`); document.querySelector(".area").innerHTML = `<option value="">地区</option>` + str; }); /** * 目标2:收集数据提交保存 * 2.1监听提交的点击事件 * 2.2依靠插件收集表单数据 * 2.3基于axios提交保存,显示结果 */ document.querySelector(".submit").addEventListener("click", async () => { try { const form = document.querySelector(".info-form"); const data = serialize(form, { hash: true, empty: true }); const result = await axios({ url: "http://hmajax.itheima.net/api/feedback", method: "post", data, }); alert(result.data.message); } catch (error) { // console.dir(error) alert(error.response.data.message); } });

来源链接:https://www.cnblogs.com/iRuriCatt/p/18636389

© 版权声明
THE END
支持一下吧
点赞6 分享
评论 抢沙发
头像
请文明发言!
提交
头像

昵称

取消
昵称表情代码快捷回复

    暂无评论内容