AJAX与Axios

发布于:2024-12-22 ⋅ 阅读:(13) ⋅ 点赞:(0)

什么是 AJAX ?

AJAX 是异步的 JavaScript 和 XML(Asynchronous JavaScript And XML)。

简单理解AJAX:是一种客户端与服务器进行网络通信技术,AJAX通常使用XMLHttpRequest 对象来发送请求和接收响应

现代开发中我们通常使用 JSON格式来进行数据的传输

为何学 AJAX?

  • 以前我们的数据都是写在代码里固定的, 无法随时变化
  • 现在我们的数据可以从服务器上进行获取,让数据变活

什么是Axios

Axios 是一个别人封装好的网络请求库,可以方便的让我们完成与服务器进行网络通讯。

浏览器端Axios是基于AJAJX对象XMLHttpRequest 来进行封装的

前端开发和鸿蒙开发都需要到Axios

官网

什么是服务器?

在网络上提供服务器的一台电脑,比如提供数据服务

服务器接口文档

Axios基本用法

咱们来看看 Axios如何使用

axios官网

// 1. 引入 axios.js 文件到自己的网页中
 <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>

// 2. 使用axios
    axios({
    url: '目标资源地址'
  }).then((res) => {
     // res是一个对象,保存了服务器返回的数据
     // ✨✨✔️其中:res.data 是保存了服务器的响应数据,我们经常使用它
  })

试一试:使用axios请求 https://api-vue-base.itheima.net/api/joke

获取一条随机笑话

实现效果:

点击【按钮】获取一条【随机的笑话】并【展示到页面】上

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>AJAX概念和axios使用</title>
</head>

<body>
  <!--
    axios库地址:https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
    省份数据地址:http://hmajax.itheima.net/api/province

    目标: 使用axios库, 获取省份列表数据, 展示到页面上
    1. 引入axios库
  -->
  <p class="my-p"></p>
  <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
  <script>
    // 2. 使用axios函数
    axios({
      // url: 'http://hmajax.itheima.net/api/province'
      url:'https://api-vue-base.itheima.net/api/joke'
    }).then(result => {
      console.log(result)
      // 好习惯:多打印,确认属性名
      console.log(result.data)
      // console.log(result.data.list.join('<br>'))
      // 把准备好省份列表,插入到页面
      document.querySelector('.my-p').innerHTML = result.data
    })
  </script>
</body>

</html>

1. 认识URL

刚刚请求的地址url并不是随意的一些字符串,他叫做 URL,也可以叫做统一资源定位符

URL:统一资源定位符(Uniform Resource Locator),简称网址,用于定位网络中的资源

  • 每个有效的 URL 都指向一个唯一的资源:网页,图片,数据,视频,音频等等

  1. URL 的组成?
    • 协议,域名,资源路径(URL 组成有很多部分,我们先掌握这3个重要的部分即可)

  1. 什么是 http 协议 ?
    • 叫超文本传输协议,规定了浏览器和服务器传递数据的格式(而格式具体有哪些今天我们就会学到)
  1. 什么是域名 ?
    • 标记服务器在互联网当中的方位,网络中有很多服务器,你想访问哪一台,就需要知道它的域名才可以

  1. 什么是资源路径 ?
    • 一个服务器内有多个资源,资源路径用于标识你要访问的资源具体的位置

2. JSON

2.1. 基本概念

什么是JSON?

JSON 是一种按照 JavaScript 对象语法的数据格式,虽然它是基于 JavaScript 语法,但它独立于 JavaScript,许多【程序环境】能够读取(解读)和生成 JSON。

链接

JSON的作用?

JSON是一个字符串,常用于存储和传递数据

语法规则:

  1. 是一个字符串(配置文件中两边可以不写引号)
  2. 属性名用双引号包裹,
  3. 属性值如果是字符串也必须用双引号包裹
  4. 对象{},数组[]
const jsonObj='{"name":"jack","age":18}'
const arr = '["你好","西兰花炒蛋"]'
const arrObj = '[{"name":"jack"},{"name":"rose"}]'

Axios默认在它的底层已经通过 JSON.parse()将服务器传过来的json字符串变成了js数据类型

2.2. JSON字符串转换

如果要在 JSON 和对象之间转换,就需要用到对应api 啦:(数组也是对象)

JSON.stringify(对象)// 转为 JSON

JSON.parse(JSON)

// JSON.parse
const jsonObj='{"name":"jack","age":18}'
const obj =  JSON.parse(jsonObj)

const jsonArr = '["你好","西兰花炒蛋"]'
const arr= JSON.parse(jsonArr)

// JSON.stringify
const p={
  name:'rose',
  age:20
}

let jsonStr = JSON.stringify(p)

3. 案例-新闻

结合刚刚测试的获取新闻数据的 URL 地址,咱们来做一个案例:

需求:

  1. 打开页面时,使用axios 请求URL https://hmajax.itheima.net/api/news 获取新闻并渲染到页面上

3.2. 完整代码

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

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }


        .box {
            padding: 5px;
        }
        .item {
            display: flex;
            padding: 10px;
            box-shadow: 1px 1px rgba(0,0,0,0.1);
            margin: 5px 0px;
        }

        .item img {
            width: 104px;
            height: 78px;
            border-radius: 5px;
        }

        .item h3 {
            font-size: 16px;
            font-weight: 500;
            height: 40px;
            line-height: 20px;
            overflow: hidden;
        }

        .left div span {
            font-size: 12px;
        }

        .left div {
            margin-top: 10px;
        }
    </style>
</head>

<body>
    <div class="box">
      <!-- <div class="item">
            <div class="left">
                <h3>一抓一放、张手就来:华为Mate 70/X6
                    系列手机、MatePad Pro 13.2 英寸平板 2..</h3>
                <div>
                    <span>新京报  2024-12-7 09:17:02</span>
                    <span>94评</span>
                </div>
            </div>
            <img src="https://img.ithome.com/newsuploadfiles/thumbnail/2024/11/812592_240.jpg" alt="">
        </div> -->
    </div>

    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
    <script>
       axios({     
      url:'https://hmajax.itheima.net/api/news'
    }).then(result => {
      console.log(result)
      // 好习惯:多打印,确认属性名
      console.log(result.data.data)
      let str = ``
      result.data.data.forEach(item=>{
        str+=`
         <div class="item">
            <div class="left">
                <h3>${item.title}</h3>
                <div>
                    <span>${item.source}  ${item.time}</span>
                    <span>${item.cmtcount}评</span>
                </div>
            </div>
            <img src="${item.img}" alt="">
        </div>
        `
      })

      // 把准备好省份列表,插入到页面
      document.querySelector('.box').innerHTML = str
    })
    </script>
</body>

</html>

4. URL 查询参数

目前咱们只能获取固定的数据,如果要查询特定的数据怎么办呢?可以通过 URL 查询参数来实现

4.1. 什么是URL查询参数

URL查询参数是提供给网络服务器的额外参数。这些参数是用 & 符号分隔的键/值对列表。在返回资源之前,Web 服务器可以使用这些参数来执行额外的操作。每个 Web 服务器都有自己关于参数的规则,唯一可靠的方式来知道特定 Web 服务器是否处理参数是通过询问 Web 服务器所有者

简而言之: 携带给服务器额外信息,让服务器返回我想要的某一部分数据而不是全部数据

咱么先通过 2 个预先准备好的地址来确认一下

百度安全验证

百度安全验证

百度安全验证

拼接在 URL 末尾的就是查询参数:

? 隔开之后使用&分隔的键值对列表

4.2. 如何确认 URL 查询参数

实际开发时,服务器的所有者会提供 URL 查询参数的信息,比如

地址:http://hmajax.itheima.net/api/city

说明获取某个省所有的城市查询

参数名:pname

说明: 传递省份或直辖市名,比如 北京、广东省…

接口说明地址

4.3. axios 如何携带查询参数?

  • 使用 params 选项即可
axios({
  url: 'http://测试服务器/资源路径',
  params: {
    key: 'value',
    key2: 'value2'
  }
}).then(res => {
  // 接受并使用数据
})

4.4. 城市查询案例(讲解)

url地址:http://hmajax.itheima.net/api/city

说明获取某个省所有的城市查询

参数名:pname

说明: 传递省份或直辖市名,比如 北京、广东省…

接口说明地址

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AJAX概念和axios使用</title>
</head>

<body>
    <input type="text" class="pname" placeholder="输入如:广东省"> <button class="query">查询城市</button>
    <p class="my-p"></p>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
    <script>

        document.querySelector('.query').addEventListener('click', function () {
            let pname = document.querySelector('.pname').value
            // 2. 使用axios函数
            axios({
                // url: 'http://hmajax.itheima.net/api/city?pname='+pname,
                url: 'http://hmajax.itheima.net/api/city',
                params:{
                    pname:pname
                }
            }).then(result => {
                console.log(result)
                // 好习惯:多打印,确认属性名
                console.log(result.data)
                // console.log(result.data.list.join('<br>'))
                // 把准备好省份列表,插入到页面
                document.querySelector('.my-p').innerHTML = result.data.list.join('<br>')
            })
        })


    </script>
</body>

</html>

4.5. 案例-查询-地区列表(自己写)

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

服务器接口文档

查询地区: http://hmajax.itheima.net/api/area

参数名:

pname:省份名字

cname:城市名字

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

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AJAX概念和axios使用</title>
</head>

<body>
    <input type="text" class="pname" placeholder="输入如:广东省"> 
    <input type="text" class="cname" placeholder="输入如:深圳市"> 
    <button class="query">查询地区</button>
    <p class="my-p"></p>
    <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.4/axios.min.js"></script>
    <script>

        document.querySelector('.query').addEventListener('click', function () {
            let pname = document.querySelector('.pname').value
            let cname = document.querySelector('.cname').value
            // 2. 使用axios函数
            axios({
                url: 'http://hmajax.itheima.net/api/area',
                params:{
                    pname:pname,
                    cname:cname
                }
            }).then(result => {
                console.log(result)
                // 好习惯:多打印,确认属性名
                console.log(result.data)
                // console.log(result.data.list.join('<br>'))
                // 把准备好省份列表,插入到页面
                document.querySelector('.my-p').innerHTML = result.data.list.join('<br>')
            })
        })


    </script>
</body>

</html>

5. 请求方法和数据提交

到目前为止都是向服务器获取数据,接下来咱们来看看如何向服务器发送数据

  1. GET请求方法是axios的默认请求方法
  2. 向服务器发送数据我们常用的方式是POST请求方法(需要显示指定)

提交数据给服务器的场景:用户登录,注册,修改密码等

5.1. Axios POST请求方法

// ✨✨需要设置method 和 data 这2个新的选项
axios({
  url:'请求URL',
  method:'post',
  data:{
    key:'value',
    key1:'value1',
    .....
  },
})

5.2. POST请求举例

使用axios的post请求实现用户注册

测试用 url

请求地址(url):http://hmajax.itheima.net/api/register

注册用户

请求方法:POST

参数:username,password

说明:username 用户名(中英文和数字组成, 最少8位),password 密码(最少6位)

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>常用请求方法和数据提交</title>
</head>

<body>
  <button class="btn">注册用户</button>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /*
      注册用户:http://hmajax.itheima.net/api/register
      请求方法:POST
      参数名:
        username:用户名(中英文和数字组成,最少8位)
        password:密码  (最少6位)

      目标:点击按钮,通过axios提交用户和密码,完成注册
    */
    document.querySelector('.btn').addEventListener('click', () => {
      axios({
        url: 'http://hmajax.itheima.net/api/register',
        method: 'POST',
        data: {
          username: 'itheima521',
          password: '12345678'
        }
      })
      .then(res=>{
        console.log(res.data);
        
      })
    })
  </script>
</body>

</html>

5.3. axios 错误处理

  1. 如果注册相同的用户名,则会遇到注册失败的请求,也就是 axios 请求响应失败了,你会在控制台看到如图的错误:

  2. 在 axios 语法中要如何处理呢?
    • 因为,普通用户不会去控制台里看错误信息,我们要编写代码拿到错误并展示给用户在页面上
  1. 使用 axios 的 catch 方法,捕获这次请求响应的错误并做后续处理,语法如下:
axios({
  // 请求选项
}).then(res => {
  // 处理数据
}).catch(err => {
  // 处理错误
})
  1. 对应代码
  document.querySelector('.btn').addEventListener('click', function () {
      // console.log('点了')
      // 通过axios提交用户数据,完成用户注册
      axios({
        url: 'http://hmajax.itheima.net/api/register',
        method: 'post',
        data: {
          username: 'itheima521',
          password: '123456'
        }
      }).then(res => {
        console.log(res.data)
      }).catch(err => {
        // 重复注册,通过弹框提示用户
        // console.log(err)
        // console.log(err.response.data)
        alert(err.response.data.message)
      })
    })

6. 接口文档

到目前为止,咱们请求的 URL 地址,请求的方法都是直接提供好了,日常开发中如何获取这些信息呢?

日常开发中一般通过【接口文档】来获取这部分信息,【接口文档】一般由后端工程师编写

咱们通过接口文档和服务器通讯这个操作,也可以叫做 【调接口】

接口文档1

接口文档2

6.1. 接口文档实践(登录)

咱们结合 登录-form 接口来完成用户登录,关注红色部分

接口文档2

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

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>案例_登录</title>
  <!-- 引入bootstrap.css -->
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.2/dist/css/bootstrap.min.css">
  <!-- 公共 -->
  <style>
    html,
    body {
      background-color: #EDF0F5;
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center;
      align-items: center;
    }

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

    .container h3 {
      font-weight: 900;
    }
  </style>
  <!-- 表单容器和内容 -->
  <style>
    .form_wrap {
      color: #8B929D !important;
    }

    .form-text {
      color: #8B929D !important;
    }
  </style>
  <!-- 提示框样式 -->
  <style>
    .alert {
      transition: .5s;
      opacity: 0;
    }

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

<body>
  <div class="container">
    <h3>欢迎-登录</h3>
    <!-- 登录结果-提示框 -->
    <div class="alert alert-success" role="alert">
      提示消息
    </div>
    <!-- 表单 -->
    <div class="form_wrap">
      <form>
        <div class="mb-3">
          <label for="username" class="form-label">账号名</label>
          <input type="text" class="form-control username">
        </div>
        <div class="mb-3">
          <label for="password" class="form-label">密码</label>
          <input type="password" class="form-control password">
        </div>
        <button type="button" class="btn btn-primary btn-login"> 登 录 </button>
      </form>
    </div>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    // 目标1:点击登录时,用户名和密码长度判断,并提交数据和服务器通信
    
    // 1.1 登录-点击事件
    document.querySelector('.btn-login').addEventListener('click', () => {
      // 1.2 获取用户名和密码
      const username = document.querySelector('.username').value
      const password = document.querySelector('.password').value
      // console.log(username, password)

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

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

</html>

7. HTTP协议

HTTP协议规定了【客户端发送的内容】及【服务器返回内容】的【格式】

咱们使用axios和服务器通讯的时候,本质上是发送和接收了符合 HTTP 协议规定的内容,接下来咱们来看看内容长啥样

7.1. 请求报文

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

请求报文的组成部分:

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

学会请求报文的查看,可以帮助我们来进行排错

7.2. 响应报文

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

响应报文组成:

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

咱们一般需要关注,响应行,响应体即可

不同于请求报文,响应报文是由服务器返回的,咱们无法修改,根据响应报文提供的信息,做出处理即可

响应行中可以获取到状态码,用来表示请求是否成功完成。

8. form-serialize 插件

  1. 我们前面收集表单元素的值,是一个个标签获取的
  2. 如果一套表单里有很多很多表单元素,如何一次性快速收集出来呢?
  3. 使用 form-serialize 插件提供的 serialize 函数就可以办到
  4. form-serialize 插件语法:
<script src="./lib/form-serialize.js"></script>
    • 使用 serialize 函数
  <form action="javascript:;" class="example-form">
    <input type="text" name="username">
    <br>
    <input type="text" name="password">
    <br>
    <input type="button" class="btn" value="提交">
  </form>

/**
       * 2. 使用serialize函数,快速收集表单元素的值
       * 参数1:要获取哪个表单的数据
       *  表单元素设置name属性,值会作为对象的属性名
       *  建议name属性的值,最好和接口文档参数名一致
       * 参数2:配置对象
       *  hash 设置获取数据结构
       *    - true:JS对象(推荐)一般请求体里提交给服务器
       *    - false: 查询字符串
       *  empty 设置是否获取空值
       *    - true: 获取空值(推荐)数据结构和标签结构一致
       *    - false:不获取空值
      */
const form = document.querySelector('.example-form')
const data = serialize(form, { hash: true, empty: true })

8.1. 使用serialize插件重写登录页面

9. 综合案例练习

  1. 页面进入的时候从服务器获取评论数据显示:接口文档
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>回车发布评论案例</title>
  <style>
    .wrapper {
      width: 800px;
      display: flex;
      justify-content: flex-end;
    }

    .wrapper textarea {
      height: 50px;
      flex: 1;
      padding: 10px;
      border-radius: 4px;
      border-color: #e4e4e4;
      background: #fff;
      outline: none;
      resize: none;
    }

    .wrapper button {
      width: 70px;
      margin-left: 10px;
      border: none;
      color: #fff;
      background: #00aeec;
      border-radius: 4px;
      cursor: pointer;
    }

    .wrapper .total {
      margin-right: 80px;
      margin-top: 5px;
      color: #999;
    }

    .list {
      width: 800px;
      border: 1px solid #efce9c;
      background-color: rgb(231, 238, 191);
      padding: 10px;
    }

    .list p {
      font-size: 12px;
    }

    .msg {
      height: 20px;
      background-color: rgb(187, 249, 248);
    }
  </style>
</head>

<body>
  <div class="wrapper">
    <textarea id="tx" placeholder="发一条友善的评论" rows="2" maxlength="200"></textarea>
    <button>发布</button>
  </div>
  <div class="wrapper">
    <span class="total">0/200字</span>
  </div>
  <div class="list">
    <p>评论信息:</p>
    <p class="msg">善语结善缘~~请发表你的评论</p>

  </div>


  <script src="./lib/axios.js"></script>
  <script>

    // 1. 获取评论方法
    function getList() {
      axios({
        url: 'https://hmajax.itheima.net/api/cmtlist',
        params: {
          page: 1
        }
      })
        .then(res => {
          let dataList = res.data.data
          let str = ''
          dataList.forEach(item => {
            str += ` <p data-id="${item.id}" class="msg">${item.content}</p>`
          })
          document.querySelector('.list').innerHTML = str
        })
        .catch(err=>{
          alert(err.response.data.message)
        })
    }


    // 2. 初始化新增数据
    function initpublishData() {
      const textBox = document.querySelector('#tx')
      textBox.addEventListener('keyup', function (e) {
        if (e.key === 'Enter') {
          axios({
            url:'https://hmajax.itheima.net/api/addcmt',
            method:'POST',
            data:{
              username:'ivan',
              content:textBox.value
            }
          }).then(res=>{
            textBox.value = ''
            // 当发表一条新评论,则重新问服务器要最新数据回来显示在页面上
            getList()
          })
          .catch(err=>{
            alert(err.response.data.message)
          })
          
        }
      })
    }
    
    // 3. 删除指定数据
    function initDelData(){
      document.querySelector('.list').addEventListener('click',function(e){
        if(e.target.tagName === 'P'){
          let id = e.target.dataset.id
          axios({
            url:'https://hmajax.itheima.net/api/delcmt',
            params:{
              id:id
            }
          })
          .then(res=>{
            // 删除成功后,问服务器要删除以后的数据
            getList()
          })
          .catch(err=>{
            alert(err.response.data.message)
          })
        }
      })
    }

   // 调用方法
    getList()
    initpublishData()
    initDelData()

  </script>
</body>

</html>