Skip to content
001

01_axios + HTTP 协议 + 接口文档

01_axios

01_axios 使用

01_什么是 AJAX

定义: 简单点说, 就是使用 XMLHttpRequest 对象与服务器通信

概念: AJAX 是浏览器与服务器进行 数据通信 的技术

002

02_怎么用 AJAX

先使用 axios 库, 与服务器进行 数据通信

  • 基于 XMLHttpRequest 封装, 代码简单, 月下载量在 14 亿次
  • Vue, React 项目中都会用到 axios

再学习 XMLHttpRequest 对象的使用, 了解 AJAX 底层原理


03_axios 使用

语法:

  1. 引入 axios.js: https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
  2. 使用 axios 函数
    1. 传入 配置对象
    2. 再用 .then 回调函数接收结果, 并做后续处理
003

04_获取省份列表数据案例

需求: 请求目标资源地址, 拿到省份列表数据, 显示到页面

目标资源地址: http://hmajax.itheima.net/api/province

004
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p class="my-p"></p>

  <!-- 1.引入 axios 库 -->
  <script src="./js/axios1.7.9.js"></script>

  <script>
    // 2. 使用 axios 函数
    axios({
      // 3.目标资源地址
      url: 'http://hmajax.itheima.net/api/province'
    }).then(result => {
      // 4.对服务器返回的数据做后续处理
      console.log(result)
      console.log(result.data.list)
      console.log(result.data.list.join('<br>'))
      
      // 5.把准备好省份列表, 插入到页面
      document.querySelector('.my-p').innerHTML = result.data.list.join('<br>') 
    })
  </script>
</body>

</html>

05_总结

AJAX 有什么用?

  • 浏览器和服务器之间通信, 动态数据交互

AJAX 如何学:

  • 先掌握 axios 使用
  • 再了解 XMLHttpRequest 原理

这一节 axios 体验步骤?

  • 引入 axios 库
  • 使 axios 语法
005

02_URL 的组成

01_认识 URL

原因: 知道作用和组成, 方便与后端人员沟通

006

02_什么是 URL

定义: 统一资源定位符 (URL), 简称 网址

例如:

007

概念: URL 就是 统一资源定位符, 简称 网址, 用于访问网络上的 资源


03_URL 的组成

008

04_协议

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

009

05_域名

域名: 标记服务器在互联网中 方位

010

06_资源路径

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

011

07_获取新闻列表数据案例

需求: 使用 axios 从服务器拿到新闻列表数据

目标资源地址: http://hmajax.itheima.net/api/news

012
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script src="./js/axios1.7.9.js"></script>

  <script>
    // 1.获取新闻列表
    axios({
      url: 'http://hmajax.itheima.net/api/news'
    }).then(result => {
      console.log(result)
    })
  </script>
</body>

</html>

08_总结

URL 是什么:

  • 统一资源定位符, 网址, 用于访问服务器上资源

请解释这个 URL, 每个部分作用?

  • http://hmajax.itheima.net/api/news
  • 协议://域名/资源路径

03_axios 查询参数

01_URL 查询参数

定义: 浏览器提供给服务器的 额外信息, 让服务器返回浏览器想要的数据

语法: http://xxxx.com/xxx/xxx?`参数名1=值1`&`参数名2=值2`

013

02_axios 查询参数

  • 语法: 使用 axios 提供的 params 选项
  • 注意: axios 在运行时把参数名和值, 会拼接到 url?参数名=值
  • 城市列表: http://hmajax.itheima.net/api/city?pname=河北省
014
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <p></p>

  <script src="./js/axios1.7.9.js"></script>

  <script>
    axios({
      url: 'http://hmajax.itheima.net/api/city',
      // 1.查询参数
      params: {
        pname: '辽宁省'
      }
    }).then(result => {
      console.log(result.data.list)
      document.querySelector('p').innerHTML = result.data.list.join('<br>')
    })
  </script>
</body>

</html>

03_总结

URL 查询参数有什么作用?

  • 浏览器提供给服务器 额外信息, 获取对应的数据

axios 要如何携带查询参数?

  • 使用 params 选项, 携带参数名和值
015

04_地区查询案例

01_地区查询案例

需求: 根据输入的省份名字和城市名字, 查询地区并渲染列表

016

首先: 确定 URL 网址参数 说明

  • 查询某个 内某个 城市 的所有地区: http://hmajax.itheima.net/api/area
  • 参数名:
    • pname: 省份名字或直辖巿名字, 比如 北京, 福建省, 辽宁省...
    • cname: 城市名字, 比如 北京市, 厦门市, 大连市...

完整: http://hmajax.itheima.net/api/area?pname=北京&cname=北京市

html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <link rel="stylesheet" href="./Bootstrap/bootstrap5.1.3.css">
  <style>
    :root {
      font-size: 15px;
    }

    body {
      padding-top: 15px;
    }
  </style>
</head>

<body>
  <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="./js/axios1.7.9.js"></script>

  <script>
    // 1.查询按钮 点击事件
    document.querySelector('.sel-btn').addEventListener('click', () => {
      // 2.获取省份和城市名字
      let pname = document.querySelector('.province').value
      let cname = document.querySelector('.city').value

      // 3.基于 axios 请求地区列表数据
      axios({
        url: 'http://hmajax.itheima.net/api/area',
        params: {
          pname,
          cname
        }
      }).then(result => {
        // 4.把数据转 li 标签插入到页面上
        let list = result.data.list
        console.log(list)
        let theLi = list.map(areaName => `<li class="list-group-item">${areaName}</li>`).join('')
        console.log(theLi)
        document.querySelector('.list-group').innerHTML = theLi
      })
    })
  </script>
</body>

</html>

05_axios 请求配置

01_常用请求方法

请求方法: 对服务器 资源, 要执行的 操作

017

02_数据提交

场景: 当数据需要在服务器上 保存

018

03_axios 请求配置

  • url: 请求的 URL 网址
  • method: 请求的方法, GET 可以省略 (不区分大小写)
  • data: 提交数据
019

04_注册账号案例

需求: 通过 axios 提交用户名和密码, 完成注册功能

020021
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <button class="btn">注册用户</button>

  <script src="./js/axios1.7.9.js"></script>

  <script>
    // 1.点击按钮, 通过 axios 提交用户和密码, 完成注册
    document.querySelector('.btn').addEventListener('click', () => {
      axios({
        url: 'http://hmajax.itheima.net/api/register',
        // 2.指定请求方法
        method: 'POST',
        // 3.提交数据
        data: {
          username: 'itheima007',
          password: '1234567'
        }
      }).then(result => {
        console.log(result)
      })
    })
  </script>
</body>

</html>

05_总结

请求方法表明对服务器资源的操作, 最为常用 的 2 个是?

  • POST 提交数据, GET 查询数据

axios 的核心配置?

  • url: 请求 URL 网址
  • method: 请求方法, GET 可以省略 (不区分大小写)
  • params: 查询参数
  • data: 提交数据
022

06_axios 错误处理

01_报错信息

场景: 再次注册相同的账号, 会遇到报错信息

处理: 用更直观的方式, 给 普通用户 展示错误信息

023

02_axios 错误处理

语法: 在 then 方法的后面, 通过点语法调用 catch 方法, 传入 回调函数 并定义 形参

024

处理: 注册案例, 重复注册 时通过 弹框 提示用户错误原因

html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <button class="btn">注册用户</button>

  <script src="./js/axios1.7.9.js"></script>

  <script>
    // 1.使用 axios 错误处理语法, 拿到报错信息, 弹框反馈给用户
    document.querySelector('.btn').addEventListener('click', () => {
      axios({
        url: 'http://hmajax.itheima.net/api/register',
        method: 'POST',
        data: {
          username: 'itheima007',
          password: '1234567'
        }
      }).then(result => {
        // 2.成功
        console.log(result)
      }).catch(error => {
        // 3.失败, 处理错误信息
        console.log(error)
        console.log(error.response.data.message)
        alert(error.response.data.message)
      })
    })
  </script>
</body>

</html>

02_HTTP 协议

01_请求报文

01_请求报文

HTTP 协议: 规定了浏览器发送及服务器返回内容的 格式

请求报文: 浏览器按照 HTTP 协议要求的 格式, 发送给服务器的 内容

025

02_请求报文的格式

请求报文的组成部分有:

  1. 请求行: 请求方法, URL, 协议
  2. 请求头: 以键值对的格式携带的附加信息, 比如: Content-Type
  3. 空行: 分隔请求头, 空行之后的是发送给服务器的资源
  4. 请求体: 发送的资源
026

03_总结

浏览器发送给服务器的内容叫做 请求报文

请求报文的组成:

027

通过 Chrome 的 网络面板 查看请求报文

028

02_请求报文 (错误排查)

01_请求报文 (错误排查)

需求: 通过请求报文排查错误原因, 并修复

输入 正确 的用户名和密码无法登录

  • 用户名: itheima007
  • 密码: 7654321
029
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <!-- 引入 bootstrap.css -->
  <link rel="stylesheet" href="./Bootstrap/bootstrap5.1.3.css">

  <!-- 公共 -->
  <style>
    html,
    body {
      background-color: #EDF0F5;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .container {
      width: 520px;
      height: 540px;
      background-color: #fff;
      padding: 60px;
      box-sizing: border-box;
    }

    .container h3 {
      font-weight: 900;
    }
  </style>

  <!-- 表单容器和内容 -->
  <style>
    .form_wrap {
      color: #8B929D !important;
    }

    .form-text {
      color: #8B929D !important;
    }
  </style>

  <!-- 提示框样式 -->
  <style>
    .alert {
      transition: .5s;
      opacity: 0;
    }

    .alert.show {
      opacity: 1;
    }
  </style>
</head>

<body>
  <div class="container">
    <h3>欢迎-登录</h3>

    <!-- 登录结果-提示框 -->
    <div class="alert alert-success" role="alert">
      JS中会动态插入提示文字
    </div>

    <!-- 表单 -->
    <div class="form_wrap">
      <form>
        <div class="mb-3">
          <label for="username" class="form-label">账号名</label>
          <input type="text" class="form-control username" name="username" aria-describedby="usernameHelp">
        </div>
        <div class="mb-3">
          <label for="password" class="form-label">密码</label>
          <input type="password" class="form-control password" name="password">
        </div>
        <button type="button" class="btn btn-primary btn-login"> 登 录 </button>
      </form>
    </div>
  </div>

  <script src="./js/axios1.7.9.js"></script>

  <script>
    // 1.获取 alert
    const alertCom = document.querySelector('.alert')

    // 2.抽取提示框的方法
    function showAlert(msg, classname) {
      alertCom.innerText = msg
      alertCom.classList.add(classname)
      alertCom.classList.add('show')
      setTimeout(() => {
        // 延迟隐藏
        alertCom.classList.remove('show')
        alertCom.classList.remove(classname)
      }, 2000);
    }

    // 3.给登录按钮绑定点击事件, 提交输入的用户信息到服务器
    document.querySelector('.btn-login').addEventListener('click', function () {
      // 4.获取输入的用户名和密码
      const username = document.querySelector('.username').value
      const password = document.querySelector('.username').value

      // 5.用户名 密码 长度判断
      if (username.trim().length < 8) {
        showAlert('用户名长度需要大于等于 8', 'alert-danger')
        return
      }
      if (password.trim().length < 6) {
        showAlert('密码长度需要大于等于 6', 'alert-danger')
        return
      }

      // 6.通过 axios 提交到服务器 并 提示用户 成功 / 失败
      axios({
        url: 'http://hmajax.itheima.net/api/login',
        method: 'post',
        data: {
          username,
          password
        }
      }).then(res => {
        // 显示提示框
        showAlert(res.data.message, 'alert-success')
      }).catch(err => {
        // 显示警示框
        showAlert(err.response.data.message, 'alert-danger')
      })
    })
  </script>
</body>

</html>

03_响应报文 + 响应状态码

01_响应报文

HTTP 协议: 规定了浏览器发送及服务器返回内容的 格式

响应报文: 服务器按照 HTTP 协议要求的 格式, 返回给浏览器的 内容

  1. 响应行 (状态行): 协议, HTTP 响应状态码, 状态信息
  2. 响应头: 以键值对的格式携带的附加信息, 比如: Content-Type
  3. 空行: 分隔响应头, 空行之后的是服务器返回的资源
  4. 响应体: 返回的资源
030

02_HTTP 响应状态码

HTTP 响应状态码: 用来表明请求 是否成功 完成

比如: 404 (服务器找不到资源)

031

03_总结

响应报文的组成:

  • 响应行 (状态行): 协议, HTTP 响应状态码, 状态信息
  • 响应头: 以键值对的格式携带的附加信息, 比如 Content-Type
  • 空行: 分隔响应头, 空行之后的是返回给浏览器的资源
  • 响应体: 返回的资源
032

HTTP 响应状态码 用来表明请求 是否成功 完成

033

03_接口文档

01_接口文档

01_接口文档

  • 接口文档: 描述 接口 的文章 (后端工程师)
  • 接口: 使用 AJAX 和服务器通讯时, 使用的 URL, 请求方法, 以及参数

传送门: AJAX 阶段接口文档 https://apifox.com/apidoc/project-1937884/doc-1695440

034

02_登录案例

035
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <button class="btn">用户登录</button>

  <script src="./js/axios1.7.9.js"></script>

  <script>
    document.querySelector('.btn').addEventListener('click', () => {
      // 1.用户登录
      axios({
        url: 'http://hmajax.itheima.net/api/login',
        method: 'post',
        data: {
          username: 'itheima007',
          password: '7654321'
        }
      })
    })
  </script>
</body>

</html>

03_总结

接口文档:

  • 后端 提供的 描述接口 的文章
036

04_登录案例

01_判断用户名和密码长度

01_判断用户名和密码长度

  1. 点击登录时, 判断用户名和密码长度
  2. 提交数据和服务器通信
  3. 提示信息
037
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <!-- 引入 bootstrap.css -->
  <link rel="stylesheet" href="./Bootstrap/bootstrap5.1.3.css">

  <!-- 公共 -->
  <style>
    html,
    body {
      background-color: #EDF0F5;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .container {
      width: 520px;
      height: 540px;
      background-color: #fff;
      padding: 60px;
      box-sizing: border-box;
    }

    .container h3 {
      font-weight: 900;
    }
  </style>

  <!-- 表单容器和内容 -->
  <style>
    .form_wrap {
      color: #8B929D !important;
    }

    .form-text {
      color: #8B929D !important;
    }
  </style>

  <!-- 提示框样式 -->
  <style>
    .alert {
      transition: .5s;
      opacity: 0;
    }

    .alert.show {
      opacity: 1;
    }
  </style>
</head>

<body>
  <div class="container">
    <h3>欢迎-登录</h3>
    <!-- 登录结果-提示框 -->
    <div class="alert alert-success" role="alert">
      提示消息
    </div>

    <!-- 表单 -->
    <div class="form_wrap">
      <form>
        <div class="mb-3">
          <label for="username" class="form-label">账号名</label>
          <input type="text" class="form-control username">
        </div>
        <div class="mb-3">
          <label for="password" class="form-label">密码</label>
          <input type="password" class="form-control password">
        </div>
        <button type="button" class="btn btn-primary btn-login"> 登 录 </button>
      </form>
    </div>
  </div>

  <script src="./js/axios1.7.9.js"></script>

  <script>
    // 1.登录 点击事件
    document.querySelector('.btn-login').addEventListener('click', () => {
      // 2.获取用户名和密码
      const username = document.querySelector('.username').value
      const password = document.querySelector('.password').value

      // 3.判断长度
      if (username.length < 8) {
        console.log('用户名必须大于等于 8 位')
        return // 阻止代码继续执行
      }
      if (password.length < 6) {
        console.log('密码必须大于等于 6 位')
        return // 阻止代码继续执行
      }

      // 4.基于 axios 提交用户名和密码
      axios({
        url: 'http://hmajax.itheima.net/api/login',
        method: 'POST',
        data: {
          username,
          password
        }
      }).then(result => {
        console.log(result)
        console.log(result.data.message)
      }).catch(error => {
        console.log(error)
        console.log(error.response.data.message)
      })
    })
  </script>
</body>

</html>

02_提示信息

01_提示信息

  1. 点击登录时, 判断用户名和密码长度
  2. 提交数据和服务器通信
  3. 提示信息
038
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <!-- 引入 bootstrap.css -->
  <link rel="stylesheet" href="./Bootstrap/bootstrap5.1.3.css">

  <!-- 公共 -->
  <style>
    html,
    body {
      background-color: #EDF0F5;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .container {
      width: 520px;
      height: 540px;
      background-color: #fff;
      padding: 60px;
      box-sizing: border-box;
    }

    .container h3 {
      font-weight: 900;
    }
  </style>

  <!-- 表单容器和内容 -->
  <style>
    .form_wrap {
      color: #8B929D !important;
    }

    .form-text {
      color: #8B929D !important;
    }
  </style>

  <!-- 提示框样式 -->
  <style>
    .alert {
      transition: .5s;
      opacity: 0;
    }

    .alert.show {
      opacity: 1;
    }
  </style>
</head>

<body>
  <div class="container">
    <h3>欢迎-登录</h3>
    <!-- 登录结果-提示框 -->
    <div class="alert alert-success" role="alert">
      提示消息
    </div>

    <!-- 表单 -->
    <div class="form_wrap">
      <form>
        <div class="mb-3">
          <label for="username" class="form-label">账号名</label>
          <input type="text" class="form-control username">
        </div>
        <div class="mb-3">
          <label for="password" class="form-label">密码</label>
          <input type="password" class="form-control password">
        </div>
        <button type="button" class="btn btn-primary btn-login"> 登 录 </button>
      </form>
    </div>
  </div>

  <script src="./js/axios1.7.9.js"></script>

  <script>
    // 1.获取提示框
    const myAlert = document.querySelector('.alert')

    // 2.封装提示框函数, 重复调用, 满足提示需求
    function alertFn(msg, isSuccess) {
      // 3.显示提示框
      myAlert.classList.add('show')

      // 4.不同提示文字 msg, 和成功绿色失败红色 isSuccess (true 成功, false 失败)
      myAlert.innerText = msg
      const bgStyle = isSuccess ? 'alert-success' : 'alert-danger'
      myAlert.classList.add(bgStyle)

      // 5.过 2 秒后, 让提示框自动消失
      setTimeout(() => {
        myAlert.classList.remove('show')

        // 提示: 避免类名冲突, 重置背景色
        myAlert.classList.remove(bgStyle)
      }, 2000)
    }

    // 登录 点击事件
    document.querySelector('.btn-login').addEventListener('click', () => {
      // 获取用户名和密码
      const username = document.querySelector('.username').value
      const password = document.querySelector('.password').value

      // 判断长度
      if (username.length < 8) {
        // 6.调用提示框函数
        alertFn('用户名必须大于等于 8 位', false)

        console.log('用户名必须大于等于 8 位')
        return // 阻止代码继续执行
      }
      if (password.length < 6) {
        // 7.调用提示框函数
        alertFn('密码必须大于等于 6 位', false)

        console.log('密码必须大于等于 6 位')
        return // 阻止代码继续执行
      }

      // 基于 axios 提交用户名和密码
      axios({
        url: 'http://hmajax.itheima.net/api/login',
        method: 'POST',
        data: {
          username,
          password
        }
      }).then(result => {
        // 8.调用提示框函数
        alertFn(result.data.message, true)

        console.log(result)
        console.log(result.data.message)
      }).catch(error => {
        // 9.调用提示框函数
        alertFn(error.response.data.message, false)

        console.log(error)
        console.log(error.response.data.message)
      })
    })
  </script>
</body>

</html>

03_form-serialize 插件

01_form-serialize 插件

作用: 快速 收集表单元素的值

039040

语法:

041
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <form action="javascript:;" class="example-form">
    <!-- 3.表单元素设置 name 属性, 值会作为对象的属性名来提交 -->
    <input type="text" name="username"><br><br>
    <input type="text" name="password"><br><br>
    <input type="button" class="btn" value="提交">
  </form>

  <!-- 1.引入 serialize 插件 -->
  <script src="./lib/form-serialize.js"></script>

  <script>
    document.querySelector('.btn').addEventListener('click', () => {
      const form = document.querySelector('.example-form')

      // 2.serialize(要获取的表单, { hash: true, empty: true })
      const data = serialize(form, { hash: true, empty: true })

      // 4.hash 设置获取数据结构 (true: JS 对象 (推荐); false: 查询字符串)
      // const data = serialize(form, { hash: true, empty: true }) // {username: 'itheima007', password: '7654321'}
      // const data = serialize(form, { hash: false, empty: true }) // username=itheima007&password=7654321

      // 5.empty 设置是否获取空值 (true: 获取空值 (推荐); false: 不获取空值)
      // const data = serialize(form, { hash: true, empty: true }) // {username: '', password: ''}
      // const data = serialize(form, { hash: true, empty: false }) // {}

      console.log(data)
    })
  </script>
</body>

</html>

04_form-serialize 登录

01_form-serialize 登录

使用 form-serialize 插件, 收集 用户名和密码

042
html
<!-- /code/test.html -->

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>

  <!-- 引入 bootstrap.css -->
  <link rel="stylesheet" href="./Bootstrap/bootstrap5.1.3.css">

  <!-- 公共 -->
  <style>
    html,
    body {
      background-color: #EDF0F5;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }

    .container {
      width: 520px;
      height: 540px;
      background-color: #fff;
      padding: 60px;
      box-sizing: border-box;
    }

    .container h3 {
      font-weight: 900;
    }
  </style>

  <!-- 表单容器和内容 -->
  <style>
    .form_wrap {
      color: #8B929D !important;
    }

    .form-text {
      color: #8B929D !important;
    }
  </style>

  <!-- 提示框样式 -->
  <style>
    .alert {
      transition: .5s;
      opacity: 0;
    }

    .alert.show {
      opacity: 1;
    }
  </style>
</head>

<body>
  <div class="container">
    <h3>欢迎-登录</h3>
    <!-- 登录结果-提示框 -->
    <div class="alert alert-success" role="alert">
      提示消息
    </div>

    <!-- 表单 -->
    <div class="form_wrap">
      <!-- 1.表单元素设置 name 属性, 值会作为对象的属性名来提交 -->
      <form class="login-form">
        <div class="mb-3">
          <label for="username" class="form-label">账号名</label>
          <input name="username" type="text" class="form-control username">
        </div>
        <div class="mb-3">
          <label for="password" class="form-label">密码</label>
          <input name="password" type="password" class="form-control password">
        </div>
        <button type="button" class="btn btn-primary btn-login"> 登 录 </button>
      </form>
    </div>
  </div>

  <script src="./js/axios1.7.9.js"></script>

  <!-- 2.引入 serialize 插件 -->
  <script src="./lib/form-serialize.js"></script>

  <script>
    // 获取提示框
    const myAlert = document.querySelector('.alert')

    // 封装提示框函数, 重复调用, 满足提示需求
    function alertFn(msg, isSuccess) {
      // 显示提示框
      myAlert.classList.add('show')

      // 不同提示文字 msg, 和成功绿色失败红色 isSuccess (true 成功, false 失败)
      myAlert.innerText = msg
      const bgStyle = isSuccess ? 'alert-success' : 'alert-danger'
      myAlert.classList.add(bgStyle)

      // 过 2 秒后, 让提示框自动消失
      setTimeout(() => {
        myAlert.classList.remove('show')

        // 提示: 避免类名冲突, 重置背景色
        myAlert.classList.remove(bgStyle)
      }, 2000)
    }

    // 登录 点击事件
    document.querySelector('.btn-login').addEventListener('click', () => {
      // 3.使用 serialize 函数, 收集登录表单里用户名和密码
      const form = document.querySelector('.login-form')
      const data = serialize(form, { hash: true, empty: true })
      console.log(data) // {username: 'itheima007', password: '7654321'}

      // 4. 获取用户名和密码, 解构赋值
      const { username, password } = data

      // 判断长度
      if (username.length < 8) {
        // 调用提示框函数
        alertFn('用户名必须大于等于 8 位', false)

        console.log('用户名必须大于等于 8 位')
        return // 阻止代码继续执行
      }
      if (password.length < 6) {
        // 调用提示框函数
        alertFn('密码必须大于等于 6 位', false)

        console.log('密码必须大于等于 6 位')
        return // 阻止代码继续执行
      }

      // 基于 axios 提交用户名和密码
      axios({
        url: 'http://hmajax.itheima.net/api/login',
        method: 'POST',
        data: {
          username,
          password
        }
      }).then(result => {
        // 调用提示框函数
        alertFn(result.data.message, true)

        console.log(result)
        console.log(result.data.message)
      }).catch(error => {
        // 调用提示框函数
        alertFn(error.response.data.message, false)

        console.log(error)
        console.log(error.response.data.message)
      })
    })
  </script>
</body>

</html>