Ajax基础


基础概念

服务器

服务器: 一台存储网站内容、网站文件的电脑

资源

资源:
1… 网站中使用的文件(html、css、图片、…)这些东西就叫做资源
2… 数据也是服务器上的资源,而且是一个网站的灵魂

客户端

客户端:
1… 客户端应该指上网的设备
2… 但是在前端开发中,可以把浏览器理解为客户端即可。

URL

url: 对服务器上的数据,进行查询、新增、修改、删除等操作,都需要URL

请求和响应

请求

1… 客户端 向服务器 要资源的 过程
2… 客户端 向服务器 提交资源的过程

3… 通过 url 地址,连接到服务器,广义上讲都叫做请求

请求是由谁发送的

客户(客户端)

什么是响应

响应: 客户端发送了请求,服务器做出的回应,叫做响应

响应是谁做出的

服务器

5种常用的请求方式

1… 获取服务器上的数据,需要使用 GET 方式
2… 新增(添加)数据,需要使用 POST 方式
3… 删除数据,需要使用 DELETE 方式
4… 完整修改(更新)数据,需要使用 PUT 方式
5… 修改(更新)部分数据,需要使用 PATCH 方式
在这里插入图片描述

了解到Ajax的作用

在这里插入图片描述

Axios库介绍

官方网站:https://www.npmjs.com/package/axios
中文网站1:https://www.axios-http.cn/
中文网站2:http://www.axios-js.com/zh-cn/docs/
使用之前,需要下载。

接口及接口文档

发送请求的时候,用什么地址?请求方式是什么?该提交哪些参数?这个请求是干什么的?
● 接口就是请求的那个地址,大家称它为 数据接口,简称接口
● 接口是后端同学设计的
● 后端同学需要出具一个接口的使用说明书,也就是接口文档
● 前端同学,要会看接口文档,会根据接口文档发送请求
●接口文档描述的是query参数或查询参数,代码要用params
●接口文档描述的是body参数或请求体,代码要用data
Ajax课上使用的接口文档:https://docs.apipost.cn/preview/f62dc0b91dc8d8ea/c31d9a50dccf65e3

加入appkey区分数据

获取图书的时候,带 params 配置:

代码如下(示例):

axios({
          method: "GET",
          url: "http://www.itcbc.com:3006/api/getbooks",
          params: {
            appkey: "zzzcccsss",
          },
        }).then((result) => {

添加图书的时候:带data配置:

代码如下(示例):

axios({
          method: "POST",
          url: "http://www.itcbc.com:3006/api/addbook",
          data: { bookname, author, publisher, appkey: "zzzcccsss" },
        }).then((result) => {

语法练习

GET请求

axios({请求的配置}).then(result=>{result.data就是响应的结果})

代码如下(示例):

<body>
    <!-- 引入axios.js -->
    <script src="./lib/axios.js"></script>

    <script>
      //  axios({请求的配置}).then(result=>{result.data就是响应的结果})
      axios({
        //键:值,
        //键:值,
        method: "GET", //指定请求方式;GET不区分大小写,建议大写
        url: "http://www.itcbc.com:3006/api/getbooks",
      }).then((result) => {
        console.log(result.data); //result.data是服务器响应的真正结果
      });
    </script>
  </body>

带条件的GET请求

带条件的查询,另一个说法是 带查询参数
在请求的配置项中,加 params配置即可。

代码如下(示例):

<body>
    <script src="./lib/axios.js"></script>
    <script>
      axios({
        method: "GET",
        url: "http://www.itcbc.com:3006/api/getbooks",
        // 加筛选条件(查询参数)
        params: {
          // id: 38258,
          bookname: "斗破苍穹",
        },
      }).then((result) => {
        console.log(result.data);
      });
    </script>
  </body>

POST请求

接口文档描述的是query参数或查询参数,代码要用params
接口文档描述的是body参数或请求体,代码要用data

代码如下(示例):

<body>
    <button>发送请求,添加图书</button>

    <script src="./lib/axios.js"></script>
    <script>
      // 点击按钮,添加图书
      document.querySelector("button").addEventListener("click", function () {
        // 按照接口文档说明,发送请求,添加图书
        axios({
          method: "POST",
          url: "http://www.itcbc.com:3006/api/addbook",
          //接口文档描述的是query参数或查询参数,代码要用params
          //接口文档描述的是body参数或请求体,代码要用data
          data: {
            bookname: "斗破苍穹134", //需求文档有填写内容要求
            author: "土豆",
            publisher: "仙侠出版社",
          },
        }).then((result) => {
          console.log(result.data);
        });
      });
    </script>
  </body>

DELETE请求

代码如下(示例):

<body>
  <button>点击删除</button>

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

  <script>
    document.querySelector('button').addEventListener('click', function () {
      // 按照axios的语法,把代码的雏形写好
      axios({
        method: 'DELETE',
        url: 'http://www.itcbc.com:3006/api/delbook',
        // 接口文档让提交 query参数,所以代码中写 params
        params: {
          id: 2213
        }
      }).then(result => {
        console.log(result.data)
      })
    })
  </script>
</body>

Network - 网络面板

面板介绍
在这里插入图片描述隐藏时间轴(可选)
在这里插入图片描述
禁用浏览器缓存
在这里插入图片描述
模拟网速(看看就行,不要乱调)
No throttling – 不限速
Fast 3G – 模拟快速3G网络
Slow 3G – 模拟慢速3G网络

在这里插入图片描述
显示请求方式
在这里插入图片描述
查看请求状态
200 表示成功
pending 表示等待(可能网络不好或者断网了)
4xx 和 5xx 都表示不同程度的错误
Failed 表示失败
在这里插入图片描述
查看提交的数据(非常重要)
在这里插入图片描述
查看响应结果(非常重要)
在这里插入图片描述

总结

在这里插入图片描述

数据回填

所以的修改,都需要数据回填。
数据回填,也叫做数据回显。就是把修改的这条数据放回到 输入框 中。
1… 具体做法一:循环遍历的时候,用 编辑 按钮的 data-xxx 属性,将数据存储起来:

代码如下:

let str = data.data.map((item) => {
            return `
              <tr>
                <th scope="row">${item.id}</th>
                <td>${item.bookname}</td>
                <td>${item.author}</td>
                <td>${item.publisher}</td>
                <td>
                  <button data-id="${item.id}" type="button" class="btn btn-link btn-sm btn-delete">删除</button>
                   <button data-id="${item.id}" data-bookname="${item.bookname}" data-author="${item.author}" data-publisher="${item.publisher}"type="button" class="btn btn-link btn-sm btn-update">编辑</button>
                </td>
              </tr>
            `;
          });

点击编辑的时候,获取这些data-xxx属性值,设置给输入框即可:

代码如下:

// 编辑
        if (ev.target.classList.contains("btn-update")) {
          editModal.show();
          // 获取4个data的值
          let add = ev.target.dataset;
          // 设置输入框的默认值
          document.querySelector("#editForm [name=id]").value = add.id;
          document.querySelector("#editForm [name=author]").value = add.author;
          document.querySelector("#editForm [name=bookname").value = add.bookname;
          document.querySelector("#editForm [name=publisher]").value = add.publisher;
        }
      });

回顾表单元素

注意事项:

表单各项,必须有name属性(和后续的数据提交有关系)
单项按钮组,多个按钮,name属性要一致,才叫做一组
单项按钮、复选按钮,都要设置value值,提交数据的时候,提交的是value值
下拉框,name属性要给 select标签;value属性要给 option标签

代码如下(示例):

   <form action="">
      单行文本框:
      <input type="text" name="username" /><br />
      密码框:
      <input type="password" name="pwd" /><br />
      单项按钮组:
      <input type="radio" value="nan" name="sex" /><input type="radio" value="nv" name="sex" /><br />
      复选按钮组:
      <input type="checkbox" name="hobby" value="cf" />吃饭
      <input type="checkbox" name="hobby" value="sj" />睡觉
      <input type="checkbox" name="hobby" value="ddd" />打豆豆<br />
      下拉框:
      <select name="address">
        <option value="bj">北京</option>
        <option value="sh">上海</option>
        <option value="gz">广州</option></select
      ><br />
      文件选择框:
      <input type="file" /><br />
      多行文本框:
      <textarea name="intro" cols="30" rows="3"></textarea><br />
      隐藏域:
      <input type="hidden" name="id" value="100" /><br />
      <!-- h5新增:
  <input type="color"> -->

      <!-- 表单中的按钮 -->
      <!-- 1.提交按钮(点击之后会造成表单提交) -->
      <button id="tijiao">提交按钮1</button>
      <button type="submit">提交按钮2</button>
      <input type="submit" value="提交按钮3" />
      <hr />
      <!-- 2.普通按钮(点击之后不会有任何反应) -->
      <button type="button">普通按钮1</button>
      <input type="button" value="普通按钮2" />
      <hr />
      <!-- 3.重置按钮(点击之后,会重置表单) -->
      <button type="reset">重置按钮1</button>
      <input type="reset" value="重置按钮2" />
    </form>

阻止表单提交行为

方案有两个:
在以后提交数据的时候,可以找到提交按钮,注册click事件;
也可以找到form,注册submit事件。最终的效果是一样的。

 // 1. ------------- 点击提交按钮 阻止默认行为----------------------------------------
      // document.querySelector('.tijiao').addEventListener('click', function (e) {
      //   e.preventDefault()
      // })

      // 2. --------------- 阻止表单提交行为 ----------------------------
      document.querySelector("form").addEventListener("submit", function (e) {
        e.preventDefault();

axios全局配置

官方参考:https://www.axios-http.cn/docs/config_defaults
全局配置了请求根路径,后面所有的请求,都不需要加请求根路径了

 // 全局配置请求根路径
      axios.defaults.baseURL = "http://www.itcbc.com:3006";
      // 全局配置了请求根路径,后面所有的请求,都不需要加请求根路径了
      axios({
        method: "GET",
        url: "/api/getbooks", //开头的斜线不能丢
      }).then((result) => {
        console.log(result.data);
      });

axios请求方法的别名(简写)

1… GET 和 DELETE

// ---------------------------- GET 和 DELETE -----------------------------------
      // 发送GET请求|发送DELETE请求   axios.get(url, { /*请求的配置*/ }).then(result => {})
      axios.get("/api/getbooks", { params: { appkey: "zcszcs" } }).then((result) => console.log(result.data));

2… POST 和 PUT 和 PATCH

// ---------------------------- POST 和 PUT 和 PATCH -----------------------------------
      // 语法  axios.post(url, data, {/*请求的配置*/})
      axios
        .post("/api/addbook", {
          bookname: "dddd",
          author: "dsds",
          publisher: "sdfsf",
          appkey: "laot334ang",
        })
        .then((result) => {
          console.log(result.data);
        });

请求拦截器和响应拦截器

<body>
  <script src="./axios.js"></script>
  <script>
    // 全局配置
    axios.defaults.baseURL = 'http://www.itcbc.com:3006'

    // 添加请求拦截器
    axios.interceptors.request.use(
      function (config) {
        // 在发送请求之前做些什么(可以在这里做一个请求的配置)
        // console.log(config.url)
        // config.url = '/api/abcd'
        return config;
      },
      function (error) {
        // 对请求错误做些什么(一般情况都不用,请求发不出去,才会执行这个函数)
        return Promise.reject(error);
      }
    );

    // 添加响应拦截器
    axios.interceptors.response.use(
      function (response) {
        // 2xx 范围内的状态码都会触发该函数。
        // console.log('状态码在 2xx 的范围内')
        alert(response.data.message)
        // 对响应数据做点什么
        return response;
      },
      function (error) {
        // 超出 2xx 范围的状态码都会触发该函数。
        // console.log('状态码超过了 2xx')
        // error.response ==== result
        alert(error.response.data.message)
        // 对响应错误做点什么
        return Promise.reject(error);
      }
    );


    // 发送请求,测试一下
    axios.get('/api/getbooks', { params: { appkey: 'laot334ang' } }).then(result => {
      console.log(result.data)
    })
  </script>
</body>

总结

在这里插入图片描述

FormData

基本使用

FormData 是一个浏览器内置对象。作用是用于获取表单数据。
● 表单各项必须有 name 属性
● let fd = new FormData(表单) // 可以把表单中的数据收集到了
● ajax提交的时候,直接提交 fd 即可

<body>
  <form action="">
    用户名:<input type="text" name="username"><br />
    密 码:<input type="password" name="pwd"><br />
    性 别:<input type="radio" value="男" name="sex"><input type="radio" value="女" name="sex"><br />
    <button>提交</button>
  </form>

  <script src="./lib/axios.js"></script>
  <script>
    axios.defaults.baseURL = 'http://www.itcbc.com:3006'
    // 点击按钮,会造成表单提交,阻止默认行为,使用 FormData 收集表单数据,Ajax提交数据
    document.querySelector('button').addEventListener('click', function (e) {
      e.preventDefault() // 阻止默认行为
      // let fd = new FormData(表单)
      let fd = new FormData(document.querySelector('form'))
      // ajax提交数据,也就是提交 fd 
      axios.post('/api/formdata', fd).then(result => {
        console.log(result.data)
      })
    })
  </script>
</body>

FormData相关的API

● fd.append(‘键’, 值) — 向原有数据中,新增一个值
● fd.delete(‘键’) — 从原有数据中,移除一个值
● fd.set(‘键’, 值) — 修改原有数据中的一个值
● fd.forEach((value, key) => {}) — 变量查看对象中有哪些数据

axios.defaults.baseURL = 'http://www.itcbc.com:3006'
// 点击按钮,会造成表单提交,阻止默认行为,使用 FormData 收集表单数据,Ajax提交数据
document.querySelector('button').addEventListener('click', function (e) {
  e.preventDefault() // 阻止默认行为
  // let fd = new FormData(表单)
  let fd = new FormData(document.querySelector('form'))
+  // 1. 向原有数据中,新增一个值
+  fd.append('phone', 1322323232)
+  // 2. 从原有数据中,删除一个值
+  fd.delete('pwd')
+  // 3. 修改一个值
+  fd.set('sex', '妖')
+  // 4. 提交前,查看有哪些数据
+  fd.forEach((value, key) => {
+    console.log(key, value)
+  })
  // ajax提交数据,也就是提交 fd 
  axios.post('/api/formdata', fd).then(result => {
    console.log(result.data)
  })
})

上传文件

原理和提交其他文本值一样,只不过上传,提交的是一个文件而已。
注意,文件选择框,name 必须是 avatar,因为接口要求的。

<body>
  <form action="">
    用户名:<input type="text" name="username"><br />
    密 码:<input type="password" name="pwd"><br />
    性 别:<input type="radio" value="男" name="sex"><input type="radio" value="女" name="sex"><br />
    头 像:<input type="file" name="avatar"><br />
    <button>提交</button>
  </form>


  <script src="./axios.js"></script>
  <script>
    axios.defaults.baseURL = 'http://www.itcbc.com:3006'
    document.querySelector('button').addEventListener('click', function (e) {
      e.preventDefault()
      // 收集表单中的数据
      let fd = new FormData(document.querySelector('form'))
      // 提交数据(数据中包括文件,提交数据,就相当于上传文件)
      axios.post('/api/formdata', fd).then(result => {
        console.log(result.data)
      })
    })
  </script>
</body>

没有form标签的情况下,如何实现文件上传:

<body>
    <input type="file" name="" id="" />
    <script src="./lib/axios.js"></script>
    <script>
      document.querySelector("input").addEventListener("change", function () {
        if (this.files.length > 0) {
          let fileObj = this.files[0];
          let fd = new FormData();
          fd.append("avatar", fileObj); //添加文件的话,要使用文件对象
          axios.post("http://www.itcbc.com:3006/api/formdata", fd).then((result) => {
            console.log(result.data);
          });
        }
      });
    </script>
  </body>

文件域补充

文件域,就是 文件选择框,也就是
课堂代码:

<body>
  <!-- 
    accept属性:控制能够选择的文件类型
     .jpg
     .jpg,.png,.gif
     image/png
     image/*
   -->
  <!-- 
    multiple属性:表示可以选择多个文件
    -->
  <input type="file" accept="image/*" multiple>

  <script>
    // 给文件选择框,注册事件的话,一般都用change事件
    document.querySelector('input').addEventListener('change', function () {
      // console.log(123)
      // 在JS中,用什么表示、来描述一个文件???
      // 文件有类型、有名字、大小、日期相关....,所以在JS中,使用对象表示文件
      // ****** 确实是使用对象来表示文件;这个对象我们不用自己创建,通过文件选择框来获得 ******

      // 获取文件对象(文件选择框的 files 属性表示我们选择的哪些个文件)
      // console.log(文件选择框.files)
      // console.log(document.querySelector('input').files)
      // console.log(this.files)
      /*
      {
        0: 文件对象,
        1: 文件对象,
        2: 文件对象,
        .............. 到底有几个结果,取决于选择了几张图片
      }
      */
      if (this.files.length > 0) {
        let fileObj = this.files[0]
        console.log(fileObj) // 用这个对象,表示我们选择的第1张图片
      }

    })





    // 表示一个人,用字符串、数组、函数、对象、布尔?????
    // 用对象,因为人的特点太多了
  </script>
</body>

本地预览:

document.querySelector('文件域').addEventListener('change', function () {
  if (this.files.length > 0) {
    let fileObj = this.files[0]  // 找到文件对象
    let url = URL.createObjectURL(fileObj) // 根据文件对象,创建url
    document.querySelector('img').src = url
  }
})

看接口文档设置请求参数和请求体

接口文档描述具体到代码
Query参数或查询参数使用学过的 params 即可 = params: { id: 200, appkey: ‘laotang’}
/api/getbooks/:id/:appkey只能自己拼接 = axios.get(‘/api/delbook/200/laotang’)
/请求体或者body参数,application/x-www-form-urlencodedaxios({ url: ‘/api/ssss’,data: ‘key=value&key=value’})
请求体或者body参数application/jsonaxios({url: ‘/api/ddd’,data: { key: value, key: value }})
请求体或者body参数multipart/form-dataaxios({url: ‘/api/ddd’,data: fd // fd 就是 new FormData()})

在这里插入图片描述

常见的响应状态码

状态码是后端同学设置的。
每一个后端同学对响应状态码的理解也是不同的。
所以,后面的学习中,或工作中,可能会遇到各种各样的状态码。
遇到什么状态码,可以去查一下:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
在这里插入图片描述

ajax原生代码

Content-Type请求头

提交的请求体,有三种格式,提交请求体的时候,必须指定对应的 Content-Type 请求头。
每种请求体,都对应着各自的Content-Type。
● 提交JSON格式数据 --------- application/json ------- 需要程序员写
● 提交查询字符串格式 --------- application/x-www-form-urlencoded ------- 需要程序员写
● 提交FormData对象 -------- multipart/form-data ------- 不需要程序员写

原生的GET请求(带参数)

// GET 和 DELETE 是一样的语法

// 1. 实例化 XMLHttpRequest 对象
let xhr = new XMLHttpRequest()

// 2. 设置 load 事件,当服务器响应结果之后,会自动触发load事件(可以在load事件中接收响应结果)
xhr.addEventListener('load', function () {
  let res = xhr.response // xhr.response 用于接收响应结果
  console.log(res)
})

// 3. 调用open方法,设置请求方式和url地址 (设置请求行)
// xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks')
// 拼接url参数,格式:   url?参数=值&参数=值&参数=值..........  (不能加任何的空格)
xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks?appkey=laot334ang')

// 4. 调用send方法,[设置请求体],发送请求
xhr.send()

原生POST请求

<body>
  <button>添加图书</button>
  
  <script>
    document.querySelector('button').addEventListener('click', function () {
      // 1. 实例化 XMLHttpRequest 对象
      let xhr = new XMLHttpRequest()
      
      // 2. 注册load事件,事件中,接收响应结果
      xhr.addEventListener('load', function () {
        let res = xhr.response
        console.log(res)
      })
      // 3. 设置open,设置请求行
      xhr.open('post', 'http://www.itcbc.com:3006/api/addbook')
      // 4. 调用 setRequestHeader() 方法,设置请求体的编码格式
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
      // xhr.setRequestHeader('Content-Type', 'application/json')
      // 5. 调用send,设置请求体,发送请求
      xhr.send('bookname=xx&author=yy&publisher=zz&appkey=laot334ang')
      // xhr.send('{ "bookname": "xx", "author": "yy", "publisher": "zz", "appkey": "laot334ang" }')
    })
    
    /*
    请求体,有三种格式:
    1. bookname=xx&author=yy&publisher=zz&appkey=laot334ang
    需要手动设置  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    
    2. '{ "bookname": "xx", "author": "yy", "publisher": "zz", "appkey": "laot334ang" }'
    需要手动设置 xhr.setRequestHeader('Content-Type', 'application/json')
    
    3. new FormData()
    不需要设置 setRequestHeader,浏览器会自动设置
    */
  </script>
</body>

封装ajax源码

// 声明函数
// 调用函数的时候,传递了一个对象格式的实参,在传参的时候,相当于把实参赋值给形参
// let { method, url, params, data } = { method: 'GET', url: 'xxxx', params: {}, data: {} }
function ajax({ method, url, params, data, success }) {
  // console.log(data)
  // 调用函数的目的就是发送Ajax请求,所以,实现Ajax请求的一套代码得写好
  let xhr = new XMLHttpRequest()
  xhr.addEventListener('load', function () {
    let res = JSON.parse(xhr.response) // 服务器返回的是JSON,这里转一下
    // console.log(res)
    success(res)
  })
  // 先处理params,把对象格式的params,转成查询字符串格式
  let arr = []
  for (let key in params) {
    arr.push(`${key}=${params[key]}`)
  }
  xhr.open(method, url + '?' + arr.join('&'))

  // 函数中,需要判断请求体的类型是什么类型的,因为不同的请求体类型,对应的 Conent-Type,send()都不同
  if (data instanceof FormData) {
    xhr.send(data)
  } else if (typeof data === 'object') {
    xhr.setRequestHeader('Content-Type', 'application/json')
    xhr.send(JSON.stringify(data)) // 需要把对象,转成JSON
  } else if (typeof data === "string") {
    xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
    xhr.send(data)
  } else {
    xhr.send()
  }
}

// 调用函数,尽量的模拟axios的封装
let fd = new FormData()
fd.append('aaa', 'hello')
ajax({
  method: 'POST',
  url: 'http://www.itcbc.com:3006/api/formdata',
  // 下面的params,有可能有
  // params: { appkey: 'laot334ang' },
  // 下面的data,模拟了可能的三种请求体
  // data: { bookname: 'ss', author: 'yy', publisher: 'dd' },
  // data: 'bookname=dd&author=yy&publisher=yys',
  data: fd,
  success: (result) => {
    console.log(result)
  }
})

同源策略和跨域请求

同源

同源,说的是两个url之间的对比。如果两个url以下三个方面都相同,则这两个url同源,否则非同源。
● 协议(http、https、file、…)
● 主机地址(www.itcbc.com)
● 端口号(:3006)
http协议默认的端口是 80; https协议默认的端口是 443
在这里插入图片描述

同源策略

同源策略(同源政策)是浏览器的一种保护机制。
如果发送了一个请求,服务器返回结果后,浏览器会判断(检查)打开页面的url 和 请求的接口地址是否同源。
● 如果同源则接收响应结果
● 如果不同源,则拒绝接收结果(造成请求失败)

跨域

定义

凡是违反了同源策略的请求,都是跨域请求。
我们这几天,请求的接口,都是跨域请求。正常来讲,都会请求失败。
目前,能够请求成功,是因为做了处理(见下文)

突破跨域的限制

正常情况下(不做任何处理的情况下),跨域请求,都不能实现。
工作中,几乎都是跨域请求。
那怎么办?
所以,我们肯定要突破跨域请求的限制才行,否则就无法正常工作了。
突破跨域的限制,可以使用JSONP方案 或 CORS方案。

CORS方案(用的多)

● 用的多
● 是标准的解决跨域的方案
● 兼容性不好(IE10+)
● 支持所有的请求方式
● 用起来方便的不要不要的
我们课程中使用的全部接口都是使用CORS方案实现的
使用CORS方案解决跨域
● 只需要后端程序员在做出响应的时候,加一个响应头(Access-Control-Allow-Origin: *)即可。
● 前面程序员不需要做任何处理,正常发送Ajax请求即可。

JSONP方案(用的少)

● 用的少
● 不是标准的解决跨域的方案
● 是一个很古老的方案
● JSONP请求,和Ajax无关,只支持GET请求。
● 了解一下实现原理即可
实现原理:
● 准备好一个函数,名字随意(比如叫做abcd),用于接收响应结果
● 使用script标签的src属性请求接口地址,并通过callback把函数名传给服务器即可

<script>
  // 提前准备好 abc 函数
  function abcd(res) {
    console.log(res)
  }
  
  // abcd({ "id": 100, "name": "hahaha", "age": 20 });
  // 你的函数名是abcd,参数是响应给你的数据哦~~~
</script>
<script src="http://www.itcbc.com:3006/api/jsonp?callback=abcd"></script>

封装一个发送JSONP请求的函数(锻炼编程能力)

function jsonp({ url, params, success }) {
  // 处理params
  let arr = []
  for (let key in params) {
    arr.push(`${key}=${params[key]}`)
  }
  // console.log(success)
  // 准备好的函数是 success
  // 服务器返回 success(.....) ,调用的是全局中的 success
  // 所以需要把我们的success升级为全局函数
  window.success = success
  let s = document.createElement('script')
  s.src = url + '?callback=success&' + arr.join('&')
  document.body.appendChild(s)
  // script标签什么时候加载完毕。当服务器返回结果后,表示script标签加载的内容加载完毕了
  // 加载完服务器返回的结果,就会触发 load 事件
  s.addEventListener('load', function () {
    document.body.removeChild(s)
  })
}

// 点击按钮,调用函数,进行测试
document.querySelector('button').addEventListener('click', function () {
  jsonp({
    url: 'http://www.itcbc.com:3006/api/jsonp',
    params: {
      id: 1,
      appkey: 'laotang'
    },
    success: function (res) {
      console.log(res)
    }
  })
})

淘宝搜索建议案例

// 分析:
// 1. 找到输入框,注册input事件(当我们在输入框输入内容的时候就会触发事件)
document.querySelector('.ipt').addEventListener('input', function () {
  // 获取搜索关键字
  let keyword = this.value
  // 2. 事件触发后,发送JSONP请求,获取搜索建议
  jsonp({
    url: 'https://suggest.taobao.com/sug',
    params: {
      q: keyword,
      code: 'utf-8'
    },
    success: (res) => {
      // 3. 得到搜索建议之后,把数据渲染到 div#suggest-list 中
      // console.log(res)
      let arr = res.result.map(item => `<div class="suggest-item">${item[0]}</div>`)
      // console.log(arr.join(''))
      document.querySelector('#suggest-list').innerHTML = arr.join('')
    }
  })
})

节流案例

let box = document.querySelector('.box')
let btn = document.querySelector('.btn-fire')
btn.addEventListener('click', function () {
  console.log(1)
  // 判断 box 盒子里面有几个图片
  if (box.children.length === 2) return
  // 创建一个热狗
  let newBall = document.createElement('img')
  newBall.src = './img/bullet.png'
  newBall.classList.add('ball')
  // 将热狗加入到盒子中
  box.appendChild(newBall)

  // 给热狗加一个动画
  for (let i = 1; i <= 95; i++) {
    setTimeout(() => {
      newBall.style.left = i + '%'
      if (i === 95) {
        // 当热狗跑到头,移除它
        box.removeChild(newBall)
      }
    }, i * 10)
  }
})

通过时间差实现节流

// 节流:单位时间(30ms)内,事件中的计算,最多执行一次
let img = document.querySelector('img')
let prev = Date.now() // 1000130
// 给 document 注册 mousemove 事件,当鼠标移动的时候触发
document.addEventListener('mousemove', function (e) {
  console.log(111)
  let curr = Date.now() // 1000130
  if (curr - prev >= 30) {
    console.log(222)
    // 获取鼠标的位置
    let x = e.clientX
    let y = e.clientY
    // console.log(x, y)
    // 设置图片的 left 样式和 top 样式
    img.style.left = (x - 30) + 'px'
    img.style.top = (y - 30) + 'px'
    // 重置上一次执行时间
    prev = Date.now()
  }

})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

郑钱钱吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值