Ajax学习总结

193 阅读3分钟

Ajax学习总结

什么是Ajax

Ajax是浏览器种的技术:用来实现客户端网页请求服务器的数据

英文全称是Asynchronous Javascript And XML,简称 Ajax。

有数据的地方就有Ajax.

请求方式

1650810084192

基本用法

axios专注于数据请求的库

中文官网地址:www.axios-http.cn/

基本语法

axios({ method: '请求的类型', url: '请求的URL地址' }).then((result) => { // then 用来指定请求成功之后的回调函数 // 形参中的 result 是请求成功之后的结果 })

get

向服务器获取数据

  1. 可以直接在url上拼接参数

    url: 'http://www.itcbc.com:3006/api/addbook?username=111&password=222'
    
  2. 使用axios方法通过params对象进行传递

    <!-- 1 引入axios -->
        <script src="./lib/axios.js"></script>
        <script>
          axios({
            method: 'get',
            url: 'http://www.itcbc.com:3006/api/getbooks',
            // 请求的参数  同时指定多个参数 (我想要买手机 颜色是蓝色 并且 内存是 256G )
            // 5913	Web开发实战
            params: {
              // 0 条数据 多个参数的含义是 && 两个条件都要满足 不是 || 或者
              // id  === 5913 && 书名 === 万少 
              // 梦想  :  我想要找 一个对象 年薪1个亿 并且 70岁以上 
              id: 5913,
              bookname: '万少',
            },
          }).then((result) => {
            console.log(result);
            const arr = result.data.data;
            render(arr);
          });
    
  3. 浏览器的地址访问接口,也是一种get请求

 axios({
          method: 'get',
          url: 'http://www.itcbc.com:3006/api/getbooks' + query,
          // params:{},
        }).then((result) => {
          console.log(result);
          const arr = result.data.data;
          render(arr);
        });
      }

post

传入参数 data

方式

  1. 字符串拼接

    axios({
             method: 'post',
             url: 'http://www.itcbc.com:3006/api/addbook',
             data:"bookname=从入门到出去123&author=我自己&publisher=黑马出版社&appkey=wanshao1234",
      
           }).then((result) => {
             console.log(result);
           });
    
  2. data对象

     axios({
             method: 'post',
             url: 'http://www.itcbc.com:3006/api/addbook',
             data: {
               bookname: '从入门到精通',
               author: '我自己',
               publisher: '黑马出版社',
               appkey: 'wanshao1234',
             },
           }).then((result) => {
             console.log(result);
           });
    
  3. formdate(可以快速获取表单提交数据,也可以作为对象传入)

    <form>
            <input type="text" name="username" value="123">
            <input type="text" name="password" value="456">
        </form>
        <script>
            const data = new FormData(document.querySelector("form"));
            const usp = new URLSearchParams(data);
            console.log(usp.toString());
        </script>
    
<button>点击按钮-加载数据</button>
    <script src="./lib/axios.js"></script>
    <script>
        const button = document.querySelector("button");
        button.addEventListener("click",function() {
            axios({
                method:'post',
                url:'http://www.itcbc.com:3006/api/addbook',
                data:{
                    // id:"6666",
                    bookname:'Java入门到入土',
                    author:'巫斌斌',
                    publisher:'503出版社',
                },
            }).then((result)=>{
                console.log(result);
            });
        });
    </script>

delete

传入参数params

axios({
                      method:'delete',
                      url:'http://www.itcbc.com:3006/api/delbook',
                      params:{id},
                  }).then((result)=>{
                      console.log(result);
                      getData();
                  });  

put

传入参数data

axios({
                method: 'put',
                url: 'http://www.itcbc.com:3006/api/updatebook',
                data,
            }).then(result => {
                booknameValue.value = "";
                authorValue.value = "";
                publisherValue.value = "";
                getData();
                // console.log(result);
                alert("修改成功");
            })

confirm弹出确认框

<button>删除</button>
    <script>
        document.querySelector("button").addEventListener("click",function() {
            if (confirm("您确定删除么?么么哒")) {
                console.log("执行删除函数");
            }else{
                console.log("取消删除");
            }
        });
    </script>

接口文档

接口

使用 Ajax 请求数据时,被请求的 URL 地址,就叫做数据接口(简称:接口或 API 接口)。

同时,每个接口必须有对应的请求方式。例如:

www.itcbc.com:3006/api/getbook… 获取图书列表的接口(GET 请求) http://www. itcbc.com:3006/api/addbook 添加图书的接口(POST 请求)

文档

接口文档就是接口的使用说明书,它是我们调用接口的依据。

格式

1650975340186

appkey身份认证

服务器存储的图书,分为通用数据个人数据

  • 默认获取、添加、删除、修改的都是通用数据。
  • 在获取、添加、删除、修改时,如果带appkey参数,则表示使用个人数据。
axios({
                method: 'get',
                url: 'http://www.itcbc.com:3006/api/getbooks',
                params: {
                    appkey: 'wanshao1234',
                }

network面板

面板介绍

img

常用设置

隐藏时间轴

img

禁用浏览器缓存

img

模拟网络(网速)

  • No throttling -- 不限速
  • Fast 3G -- 模拟快速3G网络
  • Slow 3G – 模拟慢速3G网络

img

显示请求方式

img

*查看请求状态

1650975713717

*查看请求方式和完整URL

img

*查看传输到服务器的数据

img

*查看服务器响应结果

img

form表单

表单三个属性

1650976824716

表单提交数据

标签上,通过 action 属性指定提交的 URL 地址,通过 method 属性指定提交的方式为 POST,并通过 enctype 属性指定数据的编码方式为 application/x-www-form-urlencoded:

注意:由于 enctype 的默认值就是 application/x-www-form-urlencoded,因此上述的 enctype 可以被省略!

<body>
    <!-- 
      旧方式 提交数据 form标签的方式 提交
      1 肯定会出现 刷新页面 调整页面的情况 (体验! 很糟糕)
      2 输入框没name属性 没有把数据 提交给到后端

      新的方式 ajax 
      1 异步 网络请求 (异步 同时执行多个事情 - 你一边正在使用网页功能而且数据提交 同时进行(整个网页 ))
      2 规范  只要写到input标签想要数据提交 习惯的加上 name属性
        如果使用ajax的技术来提交数据  是完全不给标签添加name属性 
      3 习惯下来  form input标签name 都一直在使用   
      
     -->
    <form action="http://www.itcbc.com:3006/api/getbooks" method="get">
      <div>
        <label for="">用户名</label>
        <input type="text" name="username">
      </div>
      <div>
        <label for="">密码</label>
        <input type="text" name="password">
      </div>
      <div>
        <label for="">随便的测试</label>
        <input type="text">
      </div>
      <!-- <button type="submit">提交</button> -->
      <button >提交</button>
    </form>

快速获取表单数据

1.jQuery 的 serialize() 函数

jQuery 的 serialize() 函数能够一次性获取到表单中采集的数据,它的语法格式如下: $('表单元素的选择器').serialize();

<body>
    <form>
      <input type="text" name="username" />
      <input type="text" name="password" />
      <input type="text" />
      <button type="button">获取表单数据</button>
    </form>
    <script src="./lib/jquery.js"></script>
    <script>
      // 序列化
      // 把对象或者数组 转成 字符串格式  过程  序列化  JSON.stringify();
      // 把字符串格式 转成 对象或者数组    反序列化   JSON.parse()
      const button = document.querySelector('button');

      // 假设我想要使用 快速获取表单数据 序列化 功能
      // 1 直接用jq的 serialize
      // 2 es6 新的对象 用这些新的对象 构造自己的序列化 方法 - 没有演示
      // 3 传统- 自己写代码 获取每一个input标签的 自己写代码进行字符串拼接  没有演示
      // 讲解js基础 对象 数组 字符串 转来转去

      button.addEventListener('click', function () {
        // 使用jq的方法 获取表单的数据 (字符串)

        // username=11&password=22  get请求 两种传递参数的方式
        // 1 params对象
        // 2 在url上拼接字符串的形式 http:/api?username=11&password=22
        // const data = $("form").serialize();
        const data = myfunc('form'); // 不要这么做 人品坏
        console.log(data);
      });

      // function $() {
      //   console.log(1);
      // }
      // $();

      function myfunc(query) {
        return $(query).serialize();
      }
    </script>

注意点

  1. 必须为每个表单域添加 name 属性!

    不然获取到的只有name属性的值,没有name属性的值获取不到

  2. 该方法是jQuery封装的,使用时必须引入jQuery

  3. 使用该方法得到的结果是一个查询字符串结构:name=value&name=value

  4. 该方法 能够 获取 隐藏域的值

  5. 该方法不能得到禁用状态的值

  6. 该方法不能得到文件域中的文件信息,所以不能完成文件上传

2.FormData

 <form>
        <input type="text" name="username">
        <input type="text" name="password">
        <input type="text" name="garden">
        <button type="button">提交</button>
    </form>

    <script>
        const button = document.querySelector("button");

        button.addEventListener("click",function() {
            const data = getForm("form");
            console.log(data);
        })

        function getForm(query) {
            //快速获取from表单中带有name属性的值,并传入到FormData中
            const form = new FormData(document.querySelector(query));
            //创建把数据转成get参数格式的对象
            // URLSearchParams URL   search  params
            const usp = new URLSearchParams(form);
            /* form.forEach((value,key)=>{
                //value = username表单的值
                //key = username;
                usp.append(key,value);
                //usp.append("username",username的值);
                //usp.append("password",password的值);
            }) */
            const data = usp.toString();
            return data;
        }
    </script>

axios简写

<script src="./lib/axios.js"></script>
    <script>
        // axios.get();
        // axios.post();
        // axios.delete();
        // axios.put();
        
        // axios.get(url); 直接在地址后面拼接参数?......
        // axios.get("http://www.itcbc.com:3006/api/getbooks?appkey=wanshao1234").then(result=>{console.log(result);})
        // axios.get(url,参数);地址后面有个对象{}里面有参数params{参数}
        // axios
        // .get("http://www.itcbc.com:3006/api/getbooks",
        //  { 
        //      params: {
        //           appkey: 'wanshao1234'
        //          } 
        //     }).then(result=>{
        //         console.log(result);
        //     })

        // axios.post(url,date) 地址  参数(对象)
        // axios.post("http://www.itcbc.com:3006/api/addbook",{
        //     bookname: '从入门到精通',
        //     author: '我自己',
        //     publisher: '黑马出版社',
        //     appkey: 'wanshao1234',
        // }).then(result=>{
        //     console.log(result);
        // })
        // axios.post(url,date) 地址  字符串
        const str = "bookname=从入门到出去123&author=我自己&publisher=黑马出版社&appkey=wanshao1234"
        axios.post("http://www.itcbc.com:3006/api/addbook",str).then(result=>{
            console.log(result);
        })
    </script>

axios拦截器

为什么要添加拦截器

有时候用户上传的文件或者图片有些大,网络又不好,上传时网页一点反应都没有对用户不友好,从而导致用户以为没提交导致一直提交,浪费服务器资源

<style>
        img {
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            display: none;
        }
    </style>
</head>

<body>
    <img src="./images/1.gif" alt="">
    <button>点击按钮</button>
    <script src="./lib/axios.js"></script>
    <script>
        const button =document.querySelector("button");
        //  发送请求的时候 都显示一个  加载中的友好提示
        // 很多功能 都需要和服务器 交互 发送网络请求
        // 上传头像  网络很慢、上传的文件很大
        // 整个页面 没有相应的 状态
        // 添加请求拦截器
        axios.interceptors.request.use(function (config) {
            // 在发送请求之前做些什么
            document.querySelector("img").style.display = "block";
            return config;
        }, function (error) {
            // 对请求错误做些什么
            return Promise.reject(error);
        });

        // 添加响应拦截器
        axios.interceptors.response.use(function (response) {
            // 2xx 范围内的状态码都会触发该函数。
            // 对响应数据做点什么
            document.querySelector("img").style.display = "none";
            return response;
        }, function (error) {
            // 超出 2xx 范围的状态码都会触发该函数。
            // 对响应错误做点什么
            return Promise.reject(error);
        });

        button.addEventListener("click",function() {
            axios.get("http://www.itcbc.com:3006/api/getbooks",{params:{appkey:"wanshao1234"}})
            .then(result=>{
                console.log(result);
            })
        })
    </script>
</body>

FormData和文件上传

  1. FormData 是一个浏览器对象。用于管理表单数据。
  2. 和 jQuery中的 serialize() 作用一样,用于快速收集表单数据
  3. 并且可以将创建的FormData对象直接提交给接口。
  4. 典型应用场景:FormData + Ajax 技术实现文件上传的功能。

使用方法

1650982355672

API方法

1650982372334

FormData和serialize的区别

1650982418493

报文

请求报文

请求报文规定了客户端以什么格式把数据发送给服务器

1651145888504

具体形式请看请求方式

响应报文

响应报文规定了服务器以什么格式把数据响应给客户端

1651145915498

http响应状态码

1651146133144

常见的http响应状态码

1651146164243

http响应状态码和业务状态码

1651146249408

1651146257677

1651146271616

原生ajax代码

XMLHttpRequest

浏览器内置的一个构造函数

作用:基于new出来的XMLHttpRequest实例对象,可以发起Ajax请求

使用XMLHttpRequest发起get请求

实现的主要4个步骤

  1. 创建xhr对象
  2. 调用xhr.open()函数
  3. 调用xhr.send()函数
  4. 监听load事件

注意:load事件也可以放到前面

<script>
        // 使用XMLHttpRequest发起get请求
        // 1.创建对象
        const xhr = new XMLHttpRequest();
        // 2.调用xhr.open()函数  方法里写请求方式  get 或者post   后面写地址
        xhr.open('get','http://www.itcbc.com:3006/api/getbooks');
        // 3.调用xhr.send()函数
        xhr.send();
        // 4.监听load事件
        xhr.addEventListener("load",function() {
            console.log("获取成功");
            // 把字符串转为对象格式输出
            const obj = JSON.parse(this.response);
            console.log(obj);
            // console.log(this.response);
        })
    </script>

原生get请求携带参数

直接把参数拼接在url地址后

<script>
        const xhr = new XMLHttpRequest();
        xhr.open('get','http://www.itcbc.com:3006/api/getbooks?appkey=wanshao1234');
        xhr.send();
        xhr.addEventListener("load",function() {
            const obj = JSON.parse(this.response);
            console.log(obj);
        })
    </script>

原生post请求携带参数(字符串)

<script>
        const xhr = new XMLHttpRequest();
        xhr.open('post','http://api.tianapi.com/hsjz/index');
        const data = {
            key:'a9f05bcff5d2146e5c44f358baad4bf1',
            content:'假如生活欺骗了你,操翻他'
        };
        // 把data转成a=1&b=2...格式 URLSearchParams
        const usp = new URLSearchParams(data);
        const query = usp.toString();

        // 设置对应的content-type
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        
        xhr.send(query);
        xhr.addEventListener('load',function() {
            console.log(this.response);
        })
    </script>

原生post请求携带参数(json对象类型)

<script>
        const xhr = new XMLHttpRequest();
        xhr.open('post','http://www.itcbc.com:3006/api/addbook');
        const data = {
            appkey:'wanshao1234',
            bookname:'假如生活欺骗了你',
            author: "222222哈哈哈",
            publisher: "33333033"
        };

        // 设置对应的content-type
        xhr.setRequestHeader("Content-Type","application/json");
        
        const str = JSON.stringify(data);
        xhr.send(str);
        xhr.addEventListener('load',function() {
            console.log(this.response);
        })
    </script>

原生post请求携带参数(FormData)

<body>
    <input type="file" accept="images/*">
    <script>
        const input = document.querySelector("input");
        input.addEventListener("change", function () {
            //获取本地文件
            const file = this.files[0];
            const formdata = new FormData();
            //插入键  值  根据接口插入键
            formdata.append("avatar", file);

            const xhr = new XMLHttpRequest();
            xhr.open('post', 'http://www.itcbc.com:3006/api/formdata');
            //不用设置Content-Type
            xhr.send(formdata);
            xhr.addEventListener('load', function () {
                console.log(this.response);
            })
        })
    </script>
</body>

post请求参数类型对应的Content-Type值

1651147050594

封装原生ajax

ajax本质可以看作一个函数

传入的参数是一个对象

需要在ajax函数中写完原生ajax代码

原生封装get

<script>
        // 1.ajax 本质可以看作一个函数
        // 2.传入的参数是一个对象格式
        // 3.需要在ajax函数中写完原生ajax代码

        const opction = {
            url:'http://www.itcbc.com:3006/api/getbooks',
            type:'get',
            data:'appkey=wanshao1234',
            success(result){
                console.log(result);
            }
        }

        ajax(opction);

        function ajax(config) {
            const xhr = new XMLHttpRequest();
            //open("请求的方式","请求地址") 如果是get请求  参数拼接在地址后面 记得加上?
            xhr.open(config.type,config.url + '?' + config.data);
            // send("写post方式可能要的参数")
            xhr.send();
            xhr.addEventListener("load",function() {
                //返回响应的数据  this.response
                // 为了更好的体验  把数据转成对象类型
                const obj = JSON.parse(this.response);
                config.success(obj);
            })
        }
    </script>

原生封装get(不带参数)

<script>

        const opction = {
            url:'http://www.itcbc.com:3006/api/getbooks',
            type:'get',
            data:'appkey=wanshao1234',
            success(result){
                console.log(result);
            }
        }

        ajax(opction);

        //形参 用解构方法 获取到里面的数据  然后给参数加上默认值
        function ajax({type,url,data="",success}) {
            const xhr = new XMLHttpRequest();
            // 封装的时候考虑到用户(可能带参数,可能不带参数)
            //地址后面直接加?不带参数的话会识别出来 没有影响
            xhr.open(type,url + '?' + data);
            xhr.send();
            xhr.addEventListener("load",function() {
                const obj = JSON.parse(this.response);
                success(obj);
            })
        }
    </script>

原生封装get(对象参数)

<script>
        ajax({
            url: 'http://www.itcbc.com:3006/api/getbooks',
            type: 'get',
            data: {
                appkey: 'wanshao1234',
                bookname: '假如生活欺骗了你'
            },
            success(result) {
                console.log(result);
            }
        });
        function ajax({ type, url, data = "", success }) {
            const xhr = new XMLHttpRequest();
            //判断传入参数是不是对象
            if (typeof data === 'object') {
                data = new URLSearchParams(data).toString();
            }
            xhr.open(type, url + '?' + data);
            xhr.send();
            xhr.addEventListener("load", function () {
                const obj = JSON.parse(this.response);
                success(obj);
            })
        }
    </script>

原生封装post

判断实例是不是 构造函数的 儿子是不是亲生的

实例 instanceof 构造函数

<body>
    <input type="file" accept="images/*">
    <script>
        //判断实例是不是 构造函数的  儿子是不是亲生的
        // 实例  instanceof  构造函数

        //对象

        // ajax({
        //     url: 'http://www.itcbc.com:3006/api/addbook',
        //     type: 'post',
        //     data: {
        //         appkey: 'wanshao1234',
        //         bookname: '假如生活欺骗了你',
        //         author: "222222哈哈哈",
        //         publisher: "33333033"
        //     },
        //     success(result) {
        //         console.log(result);
        //     }
        // });

        // 字符串

        // ajax({
        //     url: 'http://www.itcbc.com:3006/api/addbook',
        //     type: 'post',
        //     data:"bookname=%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E7%B2%BE%E9%80%9A111&author=%E6%88%91%E8%87%AA%E5%B7%B1&publisher=%E9%BB%91%E9%A9%AC%E5%87%BA%E7%89%88%E7%A4%BE&appkey=wanshao1234",
        //     success(result) {
        //         console.log(result);
        //     }
        // });

        // FormData对象
        const input = document.querySelector("input");
        input.addEventListener("change",function() {
            //获取本地文件
            const file = this.files[0];
            const formdata = new FormData();
            //插入键  值  根据接口插入键
            formdata.append("avatar", file);

            ajax({
                url: 'http://www.itcbc.com:3006/api/formdata',
                type: 'post',
                data:formdata,
                success(result) {
                    console.log(result);
                }
            });
        })



        
        function ajax({ type, url, data = "", success }) {
            const xhr = new XMLHttpRequest();
            //判断请求类型
            if (type === 'get') {
                //判断输入参数类型       
                if (typeof data === 'object') {
                    data = new URLSearchParams(data).toString();
                }
                xhr.open(type, url + '?' + data);
                xhr.send();
            } else if (type === 'post') {
                xhr.open(type, url);
                //判断参数是不是字符串
                if (typeof data === 'string') {
                    // 设置对应的content-type
                    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
                    xhr.send(data);
                } else if (typeof data === 'object') {
                    //判断参数是不是对象

                    //判断参数是不是FormData
                    if (data instanceof FormData) {
                        xhr.send(data);
                    } else {
                        //普通的对象
                        xhr.setRequestHeader("Content-Type", "application/json");
                        const str = JSON.stringify(data);
                        xhr.send(str);
                    }
                }
            }
            xhr.addEventListener("load", function () {
                const obj = JSON.parse(this.response);
                success(obj);
            })
        }
    </script>
</body>

数据交换格式JSON

1651147693613

JSON(全称:JavaScript Object Notation)是一种数据交换格式,它本质上是用字符串的方式来表示对象或数组类型的数据。

JSON数据的格式

  1. 对象格式
  2. 数组格式

语法要求

  1. 属性名必须使用双引号包裹
  2. 字符串类型的值必须使用双引号包裹
  3. JSON 中不允许使用单引号表示字符串
  4. JSON 中不能写注释
  5. JSON 的最外层必须是对象或数组格式(其他类型也可以,但多数是对象或数组格式)
  6. 不能使用 undefined 或函数作为 JSON 的值

对象格式的JSON数据

1651147867672

数组格式的JSON数据

1651147897397

把JSON格式的字符串转为JS数据

JSON.parse()

img

JS 数据转换为 JSON 格式的字符串

JSON.stringify()

img

防抖(debounce)

核心就是利用了延时器

技术原理

用新的一次输入来清除上一次的延时器

同时开启一个信的延时器

指的是:频繁触发某个操作时,只执行最后一次

应用场景

搜索框只在输入完后,才执行查询的请求。

好处

这样可以有效减少请求的次数,节省网络资源。

<body>
    <input type="text" />
    <table>
      <thead>
        <tr>
          <th>id</th>
          <th>书名</th>
          <th>作者</th>
          <th>出版社</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
    <script src="./lib/axios.js"></script>
    <script>
      /* 
      防抖  防止抖动
      1 用在输入框中 实现 不用用户按下回车键 就发送请求
      2 技术原理
        1 用新的一次输入来清除上一次的延时器 
        2 同时开启一个新的延时器 
      
       */
      getData();
      // change事件  输入框的值发生改变-输入框失去焦点 才触发
      // input 事件

      // 定义一个 演示器 id
      let timeid; // 钻 石 城 堡

      const input = document.querySelector('input');
      input.addEventListener('input', function (event) {
        clearTimeout(timeid);
        // 开启了一个延时器 里面代码 1s后会执行
        timeid = setTimeout(function () {
          const value = input.value.trim();
          const queryStr = `?bookname=${value}`;
          getData(queryStr);
        }, 1000);
      });

      function getData(query = '') {
        axios({
          method: 'get',
          url: 'http://www.itcbc.com:3006/api/getbooks' + query,
          // params:{},
        }).then((result) => {
          console.log(result);
          const arr = result.data.data;
          render(arr);
        });
      }

      function render(arr) {
        let html = arr
          .map(
            (value) => `
      <tr>
          <td>${value.id}</td>
          <td>${value.bookname}</td>
          <td>${value.author}</td>
          <td>${value.publisher}</td>
        </tr>
      `
          )
          .join('');
        document.querySelector('tbody').innerHTML = html;
      }
    </script>
  </body>

节流

指的是:单位时间内,频繁触发同一个操作,只会触发一次

应用场景

上一次请求还没结束就不能开启下一个请求

移动端分页、射击游戏中,单位时间内只能发射一颗子弹。

<body>
    <button>获取数据</button>
    <script src="./lib/axios.js"></script>
    <script>
      /* 
      节流
      上一次的业务没有结束的话 不允许开启下一次业务
      使用场景 移动端分页  -  倒计时按钮 等等 
      
       */
      
      
      
      // 这一次请求还没有结束 就不能开启下一个请求
      // 业务 分页 业务

      // 开关
      let isLoadding = false; // 有没有请求在发送当中

      // 点击按钮的时候先判断 isLoadding true还是false
      //  true 请求在发送中  return
      //  false 没有请求
      //   先设置 isLoadding true
      //   发送请求出去
      //  请求回来了  设置 isLoadding = false

      document.querySelector('button').addEventListener('click', function () {
        if (isLoadding) {
          return;
        }

        isLoadding = true;

        // 发送请求的时候  禁用按钮
        // this.disabled=true;
        getData();
      });
      function getData(query = '') {
        console.log('请求发送出去');
        axios({
          method: 'get',
          url: 'http://www.itcbc.com:3006/api/getbooks' + query,
          // params:{},
        }).then((result) => {
          console.log('数据回来了');
          // document.querySelector('button').disabled=false
          isLoadding = false;
        });
      }
    </script>
  </body>