Ajax

141 阅读21分钟

服务器概念和初始ajex

服务器相关概念

服务器

服务器的本质:也是一台电脑

服务器的作用:

  • 存储一个网站的文件(html,css,js,图片,音乐)
  • 提供网站的文件给用户

资源

  • 服务器上的 网页(html文件)、图片、音乐、视频、字体文件、CSS文件、JS文件等等都称之为资源。所以资源代指服务器上存储的内容。

  • 通俗的讲,我们浏览网页时,从网络当中看到的内容都叫做资源

    image-20220425004912887

数据也是资源

网页中的数据,也是服务器对外提供的一种资源。例如股票数据、各行业排行榜等

image-20220425005011400

服务器多数情况都使用数据表的方式来存储数据,和我们平时见到的表格差不多,形式如下

image-20220425005126381

客户端

概念:在前端开发中,客户端特指“Web 浏览器”。

作用:将互联网世界中的 Web 资源加载、并呈现到浏览器窗口中供用户使用。

常见的浏览器:

image-20220425010131207

URL地址(统一资源定位符)

URL 地址,表示服务器上每个资源的确切位置

image-20220425005339725

服务器上的每个资源,都对应着独一无二的URL地址

image-20220425005351466

数据也是服务器上的资源

对数据的操作(增删改查),也对应着不同的URL地址

image-20220425005517226

总结:

  • 可以通过URL来访问到服务器上的资源

  • 需要对应的URL来对于服务器的数据进行远程操作

(重点)客户端和服务器通信的过程

客户端与服务器之间的通信过程,分为请求 - 响应两个步骤。其中:

  • 请求的概念:客户端通过网络去找服务器要资源的过程,叫做“请求

  • 响应的概念:服务器把资源通过网络发送给客户端的过程,叫做“响应

    image-20220425005645118

    总结

    ​ 1.服务器本质就是一台电脑

    ​ 2.前端开发中,客户端指浏览器

    ​ 3.网页中资源存储在服务器中

    ​ 4.URL对服务器数据操作需要找到对应的URL地址

    ​ 5.请求是由客户端发送的,响应是由服务器做出的

    ​ 6.有数据的地方就有Ajax,数据是网页的灵魂

Ajax

思考:数据对于网页来说非常重要,那在网页中如何使用服务器的数据

答:需要用到Ajax 技术

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

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

image-20220425005808704

异步

自带定时器和延时器

  1. 代码是执行,但是结果不会马上得到

    比如下班回家吃饭,下班了但不会马上回到家

  2. 不一定按照正常上下顺序来执行代码,可以同时做多件事

    比如:和两个人吵架

  3. 异步代码:定时器和延时器

同步

  1. 代码是执行了,但是结果会马上得到

    比如:关电闸,马上就停电;或者被人揍马上就感觉到疼

  2. 按顺序一件一件做事情

    比如:做核酸

XML

  1. 类似html

  2. XML 数据格式而已,类似html数据格式

  3. 早些年代,客户端和服务器 传递数据,格式就是XML

  4. 现在主流数据格式,JSON数据格式

  5. 总结:向服务器请求数据的代码,异步;数据格式是JSON的数据格式

AJax应用场景

image-20220429001529568

请求方式

Ajax中,客户端浏览器在请求服务器上的数据时,根据操作性质(增删改查)的不同,可以分为以下 5 种常见的操作:

image-20220425010232179

操作服务器上的数据除了要使用 URL地址,还需要指定请求方式

Ajax 的基础用法

(重点)axios

axios 是前端圈最火的、专注于数据请求的库

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

英文官网地址:www.npmjs.com/package/axi…

axios操作步骤:

  1. ​ 下载 引入到项目中
  2. ​ 根据url的地址 来编写代码 ​ 1 获取数据 -get ( 请求类型 1 get 2 post 3 delete 4 put 5 patch ) ​ 2 编写代码

axios 的基本语法如下:

image-20220425010514021

then固定,是axios封装的一个代码,意思是服务器把数据返回了,then里面的代码就会被触发

基于axios发起get请求

代码案例

<!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>
      table {
       border-collapse: collapse;
       margin: 100px auto;
       border: 1px solid #000;
      }
      thead {
        background-color: rgb(177, 32, 32);
        color: white;
      }
      th{
       width: 100px;
       height: 30px;
      }
      td {
        height: 50px;
        text-align: center;
      }
    </style>
  </head>
  <body>
    <table border="1">
      <thead>
        <tr>
          <th>id</th>
          <th>书名</th>
          <th>作者</th>
          <th>出版社</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
    <!-- 第一步先下载引入axios -->
    <script src="./axios.js"></script>
    <script>
      axios({
        method: "get",
        url: "http://www.itcbc.com:3006/api/getbooks",
      }).then((result) => {
        // console.log(result)  //服务器给我们返回的数据!!
        // 数组数据
        const arr = result.data.data;  // 利用了js第三方库的帮助得到数组,
        console.log(arr);
        render(arr)
      });
      const tbody = document.querySelector("tbody");
	// 有了数组数据就可以进行页面渲染了
      function render(arr) {
        let html = ``;
        for (let index = 0; index < arr.length; index++) {
          html += ` <tr>
          <td>${arr[index].id}</td>
          <td>${arr[index].bookname}</td>
          <td>${arr[index].author}</td>
          <td>${arr[index].publisher}</td>
        </tr>`;
        }
        tbody.innerHTML = html;
      }
    </script>
  </body>
</html>

get请求的查询参数

想指定查询条件,可以通过params选项来指定查询参数

image-20220429003320989

get请求携带多个查询参数

想要携带多个参数,只需要在params对象中指定多个查询参数项即可

image-20220429003933301

get请求 直接拼接参数

url + ? 属性名=属性值&属性名=属性值

& 表示和,并且的意思

 axios({
        method: "get",
        // 写法1
         url: "http://www.itcbc.com:3006/api/getbooks",
         params:{
        id:5913
        bookname:'js高级程序设计'
        }
        // 写法2
       // url:'http://www.itcbc.com:3006/api/getbooks?id=5913' //?属性名=属性值&属性名=属性值 固定搭配
        
      //  多个参数
        url:'http://www.itcbc.com:3006/api/getbooks?id=5913&bookname=js高级程序设计' //&表示并且  
      }).then((result) => {
        // console.log(result)  //服务器给我们返回的数据!!
        // 数组数据
        const arr = result.data.data;
        console.log(arr);
        render(arr)
      });

总结

  1. 在实际开发过程中,前端可以 指定参数来查询对应的数据

  2. 指定参数的 参数的代码写法 必须要写在 params 对象中,以 键值对的形式存在

  3. params 对象中,写什么样的键值对 规定要由后端来决定 前端不懂的时候问他

接口相关的基础概念

接口

使用ajax请求数据时,被请求的URL地址,就叫做数据接口,简称接口或者API接口,每个接口必须有对应的请求方式。一般在API 接口文档中的基本信息可以看到。注意:需要使用请求接口的时候,接口URL需要和接口根路径拼接在一起

image-20220429004844655

接口文档

概念:就是接口的使用说明书,它是我们调用接口的依据。接口文档主要是后端编写的

接口文档的格式

image-20220425144119989

返回示例就是arr

image-20220425144235404

注意:后面如果Ajax程序出错,主要从接口URL,请求方式,请求参数这三方面查错

浏览器地址栏-get请求

如果直接在浏览器的地址栏输入接口地址,来访问数据,这种方式也是属于get请求

get传递参数有两种方式

1,URL上拼接 (用的是这种)

2,params指定

image-20220425152208986

image-20220425152945595

浏览器地址栏不可以测试post请求和delete请求

图书管理-增删改查

需求:根据输入框查询对应的书籍

分析如下

image-20220429005451616

关键代码

关键思路是要判断有没有查询指定参数,如果有就传递指定参数,相反如果没有的话就只是发起请求渲染页面

    getData();

      function addEvent() {
        const input = document.querySelector("input");
        input.addEventListener("keydown", (event) => {
          // 判断按下的是不是回车键
          if (event.key === "Enter") {
            const value = input.value.trim(); 
            if (value) {
              const queryStr = `?bookname=${value}`;
              getData(queryStr); //传递参数
            } else {
              getData();
            }
          }
        });
      }

完整代码

<!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>
      table {
        width: 800px;
        margin: 0 auto;
        border-collapse: collapse;
      }
      thead {
        background-color: rgb(211, 61, 61);
        height: 50px;
        color: white;
      }
      td {
        height: 50px;
        padding: 10px;
        background-color: rgb(237, 229, 229);
        text-align: center;
      }
      input {
        margin-bottom: 30px;
        margin-left: 130px;
        height: 30px;
        width: 200px;
        text-indent: 20px;
      }
    </style>
  </head>
  <body>
    <input type="text" placeholder="请输入书名" />
    <table border="1">
      <thead>
        <tr>
          <th>id</th>
          <th>书名</th>
          <th>作者</th>
          <th>出版社</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
    <script src="./axios.js"></script>
    <script>
      // <!-- 主要考的是查询指定参数,和函数参数默认值 -->
      window.addEvent();
      getData();

      function addEvent() {
        const input = document.querySelector("input");
        // const self = input;
        // console.log(input);
        input.addEventListener("keydown", (event) => {
          // 判断按下的是不是回车键
          if (event.key === "Enter") {
            // console.log("按下的是回车键");
            // 获取输入框的值
            // debugger;
            // 注意箭头函数和this一起搭配使用,this指向的是Window
            const value = input.value.trim(); // trim() 去除 输入框的值 的两侧的 空字符串
            // console.log(value);
            // 判断是不是空字符串
            if (value) {
              // 不是空字符串
              // console.log("不是空字符串");
              // 假设bookname:红楼梦 ,利用url 传参 ?属性名=属性值
              const queryStr = `?bookname=${value}`;
              // console.log(queryStr)
              getData(queryStr); //传递参数
            } else {
              // console.log("空字符串");
              getData();
            }
          }
        });
      }

      //💥 封装一个发送ajax 请求获取数据的函数
      /* 函数参数默认值
    如果没有给我传递参数,那我就输出默认值 
    如果你给我传递了参数,那我就输出你的参数*/
      // query = '' 函数参数默认值,默认空字符串
      function getData(query = "") {
        axios({
          method: "get",
          url: "http://www.itcbc.com:3006/api/getbooks" + query,
          params:{
            appkey:'dongyan123'
          }
        }).then((result) => {
          console.log(result);
          const arr = result.data.data;
          //  console.log(arr)
          render(arr);
        });
      }

      function render(arr) {
        // 遍历渲染页面
        let newArr = arr.map(
          (value) => `
         <tr>
         <td>${value.id}</td>
         <td>${value.bookname}</td>
         <td>${value.author}</td>
         <td>${value.publisher}</td>
       </tr>`
        );
        // 数组转字符串
        const html = newArr.join("");
        document.querySelector("tbody").innerHTML = html;
      }
    </script>
  </body>
</html>

需求:用户点击添加可以实现添加书籍的功能

分析如下

image-20220429005807881

关键代码

关键思路:拿到表单中的值,然后发起增加请求

      // 获取表单 dom 元素
      const booknameDom = document.querySelector(".bookname");
      const authorDom = document.querySelector(".author");
      const publisherDom = document.querySelector(".publisher");
      postData();
      // 新增内容
      function postData() {
        const button = document.querySelector("button");
        button.addEventListener("click", function () {
          // 设置 表单值
          const bookname = booknameDom.value;
          const author = authorDom.value;
          const publisher = publisherDom.value;
          const data = {
            bookname,
            author,
            publisher,
          };
          axios({
            method: "post",
            url: "http://www.itcbc.com:3006/api/addbook",
            data: {
              bookname: data.bookname,
              author: data.author,
              publisher: data.publisher,
              appkey: "dongyan123",
            },
          }).then((result) => {
            // console.log(result);
            getData(); //调用发送请求的函数
            // 清空表单值
            booknameDom.value = "";
            authorDom.value = "";
            publisherDom.value = "";
          });
        });
      }

完整代码

<!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>
      body {
        display: flex;
      }
      .left {
        width: 1000px;
        margin: 30px auto;
        /* background-color: pink; */
      }
      .right {
        flex: 1;
        padding: 20px;
        /* background-color: yellow; */
      }
      table {
        width: 850px;
        margin: 0 auto;
        border-collapse: collapse;
      }
      thead {
        background-color: rgb(211, 61, 61);
        height: 50px;
        color: white;
      }
      td {
        height: 30px;
        padding: 10px;
        text-align: center;
        background-color: rgb(245, 241, 241);
        text-align: center;
      }
      input {
        margin-bottom: 30px;
        height: 30px;
        width: 750px;
        text-indent: 20px;
      }
      h3 {
        text-align: center;
        font-size: 20px;
      }
    </style>
  </head>
  <body>
    <div class="left">
      <table border="1">
        <thead>
          <tr>
            <th>id</th>
            <th>书名</th>
            <th>作者</th>
            <th>出版社</th>
          </tr>
        </thead>
        <tbody></tbody>
      </table>
    </div>
    <div class="right">
      <form>
        <h3>添加</h3>
        <input type="text" placeholder="请输入书名" class="bookname" />
        <input type="text" placeholder="请输入作者" class="author" />
        <input type="text" placeholder="请输入出版社" class="publisher" />
        <button type="button">添加数据</button>
      </form>
    </div>
    <script src="./axios.js"></script>
    <script>
      // 获取表单 dom 元素
      const booknameDom = document.querySelector(".bookname");
      const authorDom = document.querySelector(".author");
      const publisherDom = document.querySelector(".publisher");

      postData();

      // 新增内容
      function postData() {
        const button = document.querySelector("button");
        button.addEventListener("click", function () {
          // 设置 表单值
          const bookname = booknameDom.value;
          const author = authorDom.value;
          const publisher = publisherDom.value;

          const data = {
            bookname,
            author,
            publisher,
          };

          axios({
            method: "post",
            url: "http://www.itcbc.com:3006/api/addbook",
            data: {
              bookname: data.bookname,
              author: data.author,
              publisher: data.publisher,
              // 加上了appkey 要传参,
              appkey: "dongyan123",
            },
          }).then((result) => {
            // console.log(result);
            getData(); //调用发送请求的函数
            // 清空表单值
            booknameDom.value = "";
            authorDom.value = "";
            publisherDom.value = "";
          });
        });
      }

      // 发送请求的函数
      function getData(query = "") {
        axios({
          method: "get",
          url: "http://www.itcbc.com:3006/api/getbooks" + query,
          params: {
            appkey: "dongyan123",
          },
        }).then((result) => {
          // console.log(result);
          const arr = result.data.data;

          render(arr);
        });
      }

      function render(arr) {
        // 遍历渲染页面
        let newArr = arr.map(
          (value) => `
               <tr>
               <td>${value.id}</td>
               <td>${value.bookname}</td>
               <td>${value.author}</td>
               <td>${value.publisher}</td>
             </tr>`
        );
        // 数组转字符串
        const html = newArr.join("");
        document.querySelector("tbody").innerHTML = html;
      }
    </script>
  </body>
</html>

需求:用户点击删除标签可以实现删除对应的书籍

分析如下

image-20220429010146687

关键代码

关键思路:获取到删除的id(利用自定义属性,和事件委托),再发起删除请求。优化地方:增加了内置确认框,体验感更加好

  	const tbody = document.querySelector("tbody");
      tbody.addEventListener("click", function (event) {
        if (event.target.nodeName === "A") {
          if (!confirm('确认是否删除')) {
            return  //如果不删除就不需要发出删除的请求,返回不再执行
          }
          const { id } = event.target.dataset;
          axios({
            method: "delete",
            url: "http://www.itcbc.com:3006/api/delbook",
            params: {
              id,
              appkey:'dongyan123'
            },
          }).then(result=>{
            console.log(result)
            getData() //删除成功了,发出请求,重新显示页面数据 
          });
        }
      });

完整代码

<!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>
         table {
        width: 800px;
        margin: 0 auto;
        border-collapse: collapse;
      }
      thead {
        background-color: rgb(211, 61, 61);
        height: 50px;
        color: white;
      }
      td {
        height: 50px;
        padding: 10px;
        background-color: rgb(237, 229, 229);
        text-align: center;
      }
      input {
        margin-bottom: 30px;
        margin-left: 130px;
        height: 30px;
        width: 200px;
        text-indent: 20px;
      }
    </style>
  </head>
  <body>
  
    <table border="1">
      <thead>
        <tr>
          <th>id</th>
          <th>书名</th>
          <th>作者</th>
          <th>出版社</th>
          <th>操作</th>
        </tr>
      </thead>
      <tbody></tbody>
    </table>
    <script src="./axios.js"></script>
    <script>
      const tbody = document.querySelector("tbody");
    
      // 删除
      tbody.addEventListener("click", function (event) {
        // 判断是否点击删除
        // debugger
        if (event.target.nodeName === "A") {
          // console.log('删除此id书名')
          if (!confirm('确认是否删除')) {
            // 不删除
            return //不删除不再执行下面代码
          }
          // 获取删除标签对应的id 自定义属性
          // {id} 解构成对象
          const { id } = event.target.dataset;
          axios({
            method: "delete",
            url: "http://www.itcbc.com:3006/api/delbook",
            params: {
              id,
              appkey:'dongyan123'
            },
          }).then(result=>{
            console.log(result)
            getData() //删除成功了,发出请求,重新显示页面数据 
          });
        }
      });
      getData();
      // 封装一个发送ajax 请求获取数据的函数
      function getData() {
        axios({
          method: "get",
          url: "http://www.itcbc.com:3006/api/getbooks",
          params:{
            appkey:'dongyan123'
          }
        }).then((result) => {
          // console.log(result);
          const arr = result.data.data;
          //  console.log(arr)
          render(arr);
        });
      }

      function render(arr) {
        // 遍历渲染页面
        let newArr = arr.map(
          (value) => `
         <tr>
         <td>${value.id}</td>
         <td>${value.bookname}</td>
         <td>${value.author}</td>
         <td>${value.publisher}</td>
         <td><a data-id=${value.id}   href="JavaScript:;">删除</a></td>
       </tr>`
        );
        // 数组转字符串
        const html = newArr.join("");
        document.querySelector("tbody").innerHTML = html;
      }
    </script>
  </body>
</html>

拓展知识-弹出框

confirm js中自带 确认框,如果用户点击 确定 返回true ;相反点击 取消 - false

<body>
    <button>删除</button>
    <script>
      // confirm  js中自带 确认框
      // 如果用户点击 确定 返回true  点击 取消 - false
      // confirm("您舍得删除吗😶")
      document.querySelector('button').addEventListener('click', function () {
        if (confirm('您舍得删除吗😶')) {
          //
          console.log('可以执行删除');
        } else {
          console.log('取消删除');
        }
      });
    </script>
  </body>

需求:用户点击修改标签可以实现修改对应书籍

分析如下

image-20220429010749776

关键代码

 // 需求:点击编辑按钮,获取到表单中的数据,根据接口要求把数据返回
      // 全局变量
      let arr;
      let id;
      const tbody = document.querySelector("tbody");
      const booknameDom = document.querySelector(".bookname");
      const authorDom = document.querySelector(".author");
      const publisherDom = document.querySelector(".publisher");
      const button = document.querySelector("button");

      tbody.addEventListener("click", function (event) {
        if (event.target.className === "edit") {
          const { index } = event.target.dataset;
          booknameDom.value = arr[index].bookname;
          authorDom.value = arr[index].author;
          publisherDom.value = arr[index].publisher;

          // 获取到被编辑的数据id
          id = arr[index].id;
        }
      });

      button.addEventListener("click", function () {
        // 获取表单的值
        const data = {
          // 定义一个全局变量id 就可以拿到了
          id: id,
          bookname: booknameDom.value,
          author: authorDom.value,
          publisher: publisherDom.value,
          appkey: "dongyan123",
        };
        // console.log(data)
        // 发起编辑请求
        axios({
          url: "http://www.itcbc.com:3006/api/updatebook",
          method: "put",
          data,
        }).then((result) => {
          console.log(result);
          getData();
          // 清空表单值
          booknameDom.value = "";
            authorDom.value = "";
            publisherDom.value = "";;
        });
      });

完整代码

<!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>
      body {
        display: flex;
      }
      .left {
        width: 1000px;
        margin: 30px auto;
        /* background-color: pink; */
      }
      .right {
        flex: 1;
        padding: 20px;
        /* background-color: yellow; */
      }
      table {
        width: 850px;
        margin: 0 auto;
        border-collapse: collapse;
      }
      thead {
        background-color: rgb(211, 61, 61);
        height: 50px;
        color: white;
      }
      td {
        height: 30px;
        padding: 10px;
        text-align: center;
        background-color: rgb(245, 241, 241);
        text-align: center;
      }
      h3 {
        text-align: center;
        font-size: 20px;
      }
      input {
        margin-bottom: 30px;
        height: 30px;
        width: 750px;
        text-indent: 20px;
      }
    </style>
  </head>
  <body>
    <div class="left">
      <table border="1">
        <thead>
          <tr>
            <th>id</th>
            <th>书名</th>
            <th>作者</th>
            <th>出版社</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody></tbody>
      </table>
    </div>
    <div class="right">
      <form>
        <h3>编辑</h3>
        <input type="text" placeholder="请输入书名" class="bookname" />
        <input type="text" placeholder="请输入作者" class="author" />
        <input type="text" placeholder="请输入出版社" class="publisher" />
        <button type="button">编辑数据</button>
      </form>
    </div>
    <script src="../day1/axios.js"></script>
    <script>
      // 需求:点击编辑按钮,获取到表单中的数据,根据接口要求把数据返回
      // 全局变量
      let arr;
      let id;
      const tbody = document.querySelector("tbody");
      const booknameDom = document.querySelector(".bookname");
      const authorDom = document.querySelector(".author");
      const publisherDom = document.querySelector(".publisher");
      const button = document.querySelector("button");

      tbody.addEventListener("click", function (event) {
        if (event.target.className === "edit") {
          const { index } = event.target.dataset;
          booknameDom.value = arr[index].bookname;
          authorDom.value = arr[index].author;
          publisherDom.value = arr[index].publisher;

          // 获取到被编辑的数据id
          id = arr[index].id;
        }
      });

      button.addEventListener("click", function () {
        // 获取表单的值
        const data = {
          // 定义一个全局变量id 就可以拿到了
          id: id,
          bookname: booknameDom.value,
          author: authorDom.value,
          publisher: publisherDom.value,
          appkey: "dongyan123",
        };
        // console.log(data)
        // 发起编辑请求
        axios({
          url: "http://www.itcbc.com:3006/api/updatebook",
          method: "put",
          data,
        }).then((result) => {
          console.log(result);
          getData();
          // 清空表单值
          booknameDom.value = "";
            authorDom.value = "";
            publisherDom.value = "";;
        });
      });

      getData();
      // 发送请求的函数
      function getData(query = "") {
        axios({
          method: "get",
          url: "http://www.itcbc.com:3006/api/getbooks" + query,
          params: {
            appkey: "dongyan123",
          },
        }).then((result) => {
          // console.log(result);
          arr = result.data.data;
          render(arr);
        });
      }

      function render(arr) {
        // 遍历渲染页面
        let newArr = arr.map(
          (value, index) => `
                     <tr>
                     <td>${value.id}</td>
                     <td>${value.bookname}</td>
                     <td>${value.author}</td>
                     <td>${value.publisher}</td>
                     <td><a class='edit' data-index=${index}  href="JavaScript:;">编辑</a></td>
                   </tr>`
        );
        // 数组转字符串
        const html = newArr.join("");
        tbody.innerHTML = html;
      }
    </script>
  </body>
</html>

(重点)network面板(网络)

作用:用来排查ajax方面的错误

使用该工具,可以查看当前Ajax请求的详细信息

  • 查看请求方式

  • 查看请求的URL地址

  • 查看请求参数(载荷那边看)

  • 查看响应结果(预览和响应)

  • image-20220429011240386

  • 隐藏时间轴。初学阶段,用不到时间轴,可以将其隐藏,从而节省面板的空间

image-20220429011944496

  • 禁止浏览器缓存

image-20220429011642254

  • 模拟网速

    image-20220429012105105

  • (重点)查看请求状态

    image-20220429012439637

    200 表示成功

    pending 表示等待(可能网络不好或者断网了)

    4xx 和 5xx 都表示不同程度的错误

    Failed 表示失败

  • (重点)查看请求方式和完整URL

    image-20220429012850137

  • (重点)查看传输到服务器的数据

    image-20220429013508194

  • (重点)查看服务器响应结果

    image-20220429013739493

from表单&文件上传

from表单

1、表单作用

在网页中,表单主要负责数据采集功能。例如:

image-20220501121640059

2、表单组成部分

网页中采集数据的表单由三个部分组成,分别是表单标签、表单域(一般有input,textarea、select)、表单按钮。

image-20220501122444841

当表单数据填写完毕后,用户点击表单按钮,会触发表单的提交操作,从而把采集到的数据提交到服务器

把表单采集到的数据提交到服务器时,需要指定的请求方式和请求的URL地址

思考:form表单如何指定请求的URL地址和请求方式?

使用form标签中的3个专有属性

3、form标签的属性一览表

image-20220501163914733

4、提交数据

利用form表单input带name属性可以实现提交表单数据

<body>
    // 需要指定请求方式和 URL地址
    <form action="http://www.itcbc.com:3006/api/getbooks" method="get">
        <div>
            <label for="">用户</label>
            <input type="text" name="username">
        </div>
        <button>提交</button>
    </form>
</body>

通过Ajax提交表单数据

作用:可以防止表单默认提交行为导致的页面跳转问题,提高用户体验

特点

​ 1.监听表单提交事件

​ 2.阻止默认提交行为

​ 3.基于axios发起请求

​ 4.指定请求方式,请求地址

​ 5.指定请求体数据

总结

​ 1.旧方式提交数据 直接在form标签操作方式提交

​ 2.旧方式 会刷新页面 调整页面情况,用户体验差

​ 3.如果input不加name属性,数据就不会提交到后端

​ 4.Ajax方法是异步 网络请求,这样用户体验好(一边使用功能,同时提交数据)

​ 5.Ajax技术 是完全可以不给标签加name的,只是习惯下来的行业规范

5、快速获取到form表单所有的数据

系列化

系列化:把对象或者数组转成 字符串格式的过程 JSON.stringify()

反序列化:把字符串格式转成对象或者数组的过程 JSON.parse()

URLSearchparame对象的作用是将表单或者普通对象转换成a=1&b=2 的格式

方法一、使用jq的方法serialize()函数, 获取表单的数据

作用:是jQuery的一种函数,能够一次性获取表当中采集的数据

语法:$(“表单元素的选择器”).seroalize()

<!-- 引入JQ的js文件 -->
    <script src="./lib/jquery.js"></script>
    <script>
        const btn = document.querySelector(`button`)
        btn.addEventListener(`click`,function(){
            const data = $(`form`).serialize()
            console.log(data);
        })
    </script>
复制代码

总结

​ 1.使用此函数,必须为每一个表单域添加name属性

1650958335218

​ 2.是JQ封装的,使用要引入

​ 3.结果是一个查询字符串结构

​ 4.能获取隐藏域的值,不能得到禁用状态的值,不能得到文件域的信息

方式二、自己封装函数快速获取表单数据-利用了formData(js内置的对象)

<script>
function getForm(query) {
            // JS内置对象处理表单数据把所有表单标签-name属性 要new 
            //💥补充说明  form 对象,包含所有表单数据(input name属性)
 			//操作步骤 1 快速 把 form表单中的带有name属性的数据 设置到 formdata 中
            const form = new FormData(document.querySelector(query))
            //💥补充说明 URL Search Params 用来处理 url上的参数 对象 也是可以被new
           // 操作步骤2 创建把数据 转成 get 参数格式 对象
            const usp = new URLSearchParams()
            //💥补充说明 forEach((值,键)) 固定写法 要对form遍历 出处理好的数据
            // 操作步骤3 对form遍历
            form.forEach((value,key)=>{
                // 这是url的一种方法 添加 追加
                usp.append(key,value)
            })

            // 💥补充说明 usp 有一个方法 toString()  把添加到它身上的 数据 转成 url 的参数的格式
     		// 操作步骤4 usp 获取到了所有它等待转化的数据  开始进行转化
            const data = usp.toString()
            return data
        }
</script>

总结

1.new FormData获取表单 name属性所有标签

2.new URLsearchparams 处理数据 转成get的字符串格式

3.usp.append(键,值) 添加数据

4.usp.toString()转换添加的数据

方式三、es6 新的对象 用这些新的对象 构造自己的序列化 方法

axios请求方法的别名

axios执行post请求传参格式

axios 执行post请求传递参数 data传参

data可以接受参数的类型

  • 对象类型

    data:{

    bookname:'西游记'

    autuor:'吴承恩'

    }

  • 字符串格式类型

    image-20220426154109956

普通对象快速转字符串

![image-20220528120932543](ajax.assets/image-20220528120932543.png

image-20220528121105005

axios简写的代码

get 请求

写法一: axios.get(Url)

写法二:axios.get(Url,{params:{参数}}) ;

post请求

写法一:axios.post(url,参数(对象));

  axios.post('http://www.itcbc.com:3006/api/addbook', {
          bookname: 'post请求1',
          author: 'post请求222',
          publisher: 'post请求33',
          appkey: 'wanshao1234',
        })
        .then((result) => {
          console.log(result);
        });

写法二: axios.post(url,参数(字符串格式));

 const url = 'http://www.itcbc.com:3006/api/addbook';
      const query =
        'bookname=111222&author=222222&publisher=33333&appkey=wanshao1234';
      axios.post(url, query).then((result) => {
        console.log(result);
      });

axios全局配置和拦截器

全局配置

全局配置请求根路径

image-20220528121903581

全局配置请求根路径 - 语法格式

基于 axios 提供的固定配置,即可轻松配置请求的根路径。语法格式如下: axios.defaults.baseURL = '请求根路径'

image-20220528122058032

拦截器

概念

拦截器(interceptors)用来全局拦截 axios 的每一次请求与响应。给用户一个友好提示现在加载中,防止用户一直点击

好处

可以把每个请求中,某些重复性的业务代码封装到拦截器中,提高代码的复用性。

换个简单例子说:我们出省,出省要做核酸检查;我们回来,验核酸再让你回来

使用场景

​ 很多功能 都需要和服务器 交互 发送网络请求

当上传头像  网络很慢、上传的文件很大,整个页面 没有相应的 状态

​ 这个时候,发送请求的时候 都显示一个 加载中的友好提示,这样用户体验感就比较好

实现方式

1、html+CSS来实现加载中
  • 1 .很多的ul框架 全部都会提供 加载中的 小小效果

  • 2 自己来简单写一个加载中 即可

2 自己根据发送的请求来 显示加载中! axios内置的拦截器代码功能 在任意的请求(推荐这种,因为后期项目复杂, 几百个接口 - 几百个网络请求,这样就可以统一设置)
    1. 在发送请求前 拦截 处理一下 - 显示加载中
  • 2.在数据响应来 拦截 处理一下 - 关闭加载中

<script>
       // 添加请求拦截器
      axios.interceptors.request.use(
        function (config) {
          // 在发送请求之前做些什么
          // console.log('发送前 拦截器 ');
          document.querySelector('img').style.display = 'block';
          return config;
        },
        function (error) {
          // 对请求错误做些什么
          return Promise.reject(error);
        }
      );

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

      const button = document.querySelector('button');
      button.addEventListener('click', function () {
        // 发送网络请求
        axios
          .get('http://www.itcbc.com:3006/api/getbooks?appkey=wanshao1234')
          .then((result) => {
            console.log(result);
          });
      });
    </script>

FormData 和文件上传

FormData

介绍

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

FormData基本用法-快速收集表单数据

💥要求,每个表单元素都具有 name 属性

	<body>
    <form>
      <input type="text" name="username" />
      <input type="text" name="password" />
      <input type="text" name="gender" />
      <button type="button">获取表单数据</button>
    </form>
    <script>
      // JS内置对象处理表单数据把所有表单标签-name属性 要new 
       //  form 对象,包含所有表单数据(input name属性)
        // 1 快速 把 form表单中的带有name属性的数据 设置到 formdata 中
        const form = new FormData(document.querySelector('form'));
        // 2 创建把数据 转成 get 参数格式 对象
        const usp = new URLSearchParams();
        // 3 对form遍历
        form.forEach((value, key) => {
          // value =  username表单的值
          // key = username
          usp.append(key, value);
        });
        // 4 usp 获取到了所有它等待转化的数据  开始进行转化
        const data = usp.toString();
        console.log(data);
      });
    </script>
  </body>

FormData的API方法

image-20220528152951986

FormData和serialize的区别

image-20220528153056231

文件上传-图片

操作步骤

第一步、先允许用户选择本地的图片

  • 1.1 、指定文件上传的类型,只能是图片不能是其他 input标签一个属性 指定上传的文件的类型 accept

用法

accept= 文件类型/*

accept = "image/*"
          accept = "image/*,video/*"
          https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/Input/file#唯一文件类型说明符

指定多个文件类型用法,用逗号分隔

image-20220426164959265

  • 1.2、给input标签绑定 change事件,图片上传浏览器内存中,就会触发

  • 1.3、this.files 来获取文件数组

  • 1.4、可选:先在网页显示一下用户选择的图片 再次确定是不是这个图片

      <body>
        <img src="" alt="" />
        <input type="file" accept="image/*" />
        <script>
          const input = document.querySelector("input");
          const img = document.querySelector("img");
          input.addEventListener("change", function () {
        	 // console.log("浏览器拿到图片文件了");
            // console.log(this.files);
            // 获取某个文件对象,比如第一个文件的文件对象  
            const file = this.files[0]; // 要上传的文件对象
            // 新的js对象 把浏览器内存中图片文件的地址 获取出来
    		// 创建本地文件的预览url
            const src = URL.createObjectURL(file);
            // 设置图片的src为url, 让图片显示出来
            img.src = src;
          });
        </script>
      </body>
    

    总结:

    1.明确文件上传类型:image/* 指定图片

    2.明确事件类型,change事件,上传图片触发函数

    3.URL.createObjectURL()获取浏览器中图片文件地址

第二步、把图片上传到指定服务器

  • ​ 根据接口文档的要求来操作代码

    ​ URL,请求类型,请求参数(重点)

    image-20220426171243408

    请求参数-上传文件给后端的参数 肯定是formdata 类型

<body>
     <img src="" alt="" />
   <input type="file" accept="image/*" />
     <script src="./lib/axios.js"></script>
     <script>
       const input = document.querySelector('input');
       const img = document.querySelector('img');
       input.addEventListener('change', function () {
         // 获取某个文件对象,比如第一个文件的文件对象
         const file = this.files[0];
         const src = URL.createObjectURL(file);
         img.src = src;
 
         // 参数名称 avatar  参数值 file
 
         const formdata = new FormData(); // 创建一个空formdata对象
         formdata.append('avatar', file); // 接口要求 把文件追加到 formdata对象
 
         // 把数据上传到服务器中 即可
         axios({
           method: 'post',
           url: 'http://www.itcbc.com:3006/api/formdata',
           data: formdata,
         }).then((result) => {
           console.log(result);
         });
 
         // 简写
         // axios
         //   .post('http://www.itcbc.com:3006/api/formdata', formdata)
         //   .then((result) => {
         //     console.log(result);
         //   });
       });
     </script>
   </body>

总结

1.把图片上传服务器,根据接口文档、URL、请求类型、请求参数

2.运用FormData上传文件

3.使用FormData的appen方法

文件上传完整写法

 <body>
    <input type="file" accept="image/*" />
    <script src="./lib/axios.js"></script>
    <script>
    
      const input = document.querySelector('input');
      input.addEventListener('change', function () {
        const file = this.files[0];
        const formdata = new FormData();
        // 接口要求 键值对的
        formdata.append('avatar', file);

        axios
          .post('http://www.itcbc.com:3006/api/formdata', formdata)
          .then((result) => {
            console.log(result);
          });
      });

文件域补充

input标签的属性

  • 文件域:

  • accept 属性:控制能够选择的文件类型,比如 accept="image/png,image/jpeg"

  • multiple 属性:控制是否可以多选文件

文件对象

  • 面向对象中,讲过,JS中表示一个人,需要用到对象。
  • JS中表示一个文件,也需要用对象,也就是文件对象
  • 文件对象,是本地文件的一个表示。
  • 通俗的说,在 JavaScript 中,使用 文件对象 表示一个本地文件
  • 文件对象不需要自己创建,可以通过文件域获取得到
    • 💥选择一个或多个文件
    • 💥根据文件域,找到它的 files 属性。files属性是一个伪数组,里面包含了一个或多个文件对象

取得文件对象

image-20220528160813683

文件对象的作用一:本地预览

image-20220528160851531

文件对象的作用之二:追加到FormData,实现文件上传

image-20220528160915872

请求-响应报文

本质:客户端与服务器通信的过程是基于请求和响应的。

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

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

作用:方便我们做代码的调试

请求&响应报文-格式

1.请求报文:请求行,请求头,空行和请求体4个部分组成

1651114597282

2.响应报文:状态栏,响应头部,空行和响应体4个部分组成

1651114841844

URL参数

本质:常用的5种请求方式,都可以在URL后面携带请求参数

缺点:敏感信息会直接暴露在地址栏

写法:常用的请求参数有两种写法(第二种先了解)

1651115283205

<script>
	//写法1 get(URL)
      axios.get("http://www.itcbc.com:3006/api/getbooks?appkey=HZD123")
      	.then((result)=>{
            console.log(result);
        })
        
    //写法2 get(URL,{params:参数})
      axios.get("http://www.itcbc.com:3006/api/getbooks",{params:{appkey:`HZD123`}})
        .then((result)=>{
            console.log(result);
        })
</script>
复制代码

请求体

本质:除了GET请求以外,其他4种常用的请求方式,都可以设置请求体

作用:请求体大小没有限制,所以可以提交大量的数据

写法

1651116662988

<script>
  // 写法1 axios.post(url,参数{对象}) --JSON格式
  axios.post("http://www.itcbc.com:3006/api/addbook?appkey=HZD123",{bookname:`陈某`,appkey:`XXX`})
            .then((result)=>{
            console.log(result);
        })

 // 写法2 axios.post(url,参数(字符串)) --查询字符串格式
 axios.post("http://www.itcbc.com:3006/api/addbook?appkey=HZD123",`bookname=陈某&appkey=XXX`)
            .then((result)=>{
            console.log(result);
        })
    
 // 写法3:newFormData() --- FormData 对象格式
 axios.post(`http://www.itcbc.com:3006/api/formdata`
            ,formdata)
     		.then((result)=>{
            console.log(result);
        })
</script>

注意:请求的时候,设置了不同格式的请求体,需要一个对应的请求头

1651117556460

http响应状态码

本质:http响应状态码由三位数字组成,用来标识响应成功与否的状态

作用:客户端浏览器根据响应状态码,即可判断这次http请求是否成功

1651117653644

常见的http响应状态码

1651117668484

与业务状态码区分

本质:所处的位置,表示的结果,通用性不同

1.所处的位置不同

​ 在响应头的状态行中所包含的状态码,或者请求列表中的Status

1651127609019

​ 业务状态码在响应体的数据中所包含的状态码,如案例中的code

1651127644100

2.表示的结果不同

​ 响应状态码只能表示这次请求是否成功

​ 业务状态码·表示这次业务处理是否成功

3.通用性不同

​ 响应状态码是由http协议规定的,具有通用性。每个不同的状态码都有标准含义

​ 业务状态码是后端程序员自己定义的,不具有通用性(如聚合,天行,百度等API的接口)

1651127825494

XMLHttpRequest&跨域

XMLHttpRequest

本质:是浏览器内置的一个构造函数

作用

​ 1.基于new出来的XHR实例对象,可以发起Ajax的请求。

​ 2.axios中的axios.get() .post()等方法都是基于XHR来的,XHR是原生(底层)代码

XHR发起GET请求

实现步骤

1651135959681

<script>
     // 1 创建 xhr对象
 	const xhr = new XMLHttpRequest
   // 2 调用 open方法 指定 请求类型,url
	 xhr.open(`get`,`http://www.itcbc.com:3006/api/getbooks`)
      // 3 发送出去 send
 	xhr.send()
   // 4 监听onload  数据响应事件
 	xhr.addEventListener(`load`,function(){
     console.log(this.response); //默认 是字符串的格式
	// 字符串转对象
     const obj = JSON.parse(this.response)// 反序列化
     console.log(obj.data);
 })
</script>

请求时携带URL参数

1651139454960

get方法携带参数

<script>
        const xhr = new XMLHttpRequest
        xhr.open(`get`,`http://www.itcbc.com:3006/api/getbooks?appkey=HZD123`)
        xhr.send()
        xhr.addEventListener(`load`,function(){
            console.log(this.response);
            const obj = JSON.parse(this.response)
            const arr = obj.data
            console.log(arr);
            const html = arr.map((value)=>`<li>${value.bookname}</li>`).join(``)
            document.querySelector(`ul`).innerHTML=html
        })
    </script>

post提交请求体数据时

1.调用xhr.setRequestHeader()函数,指定请求体编码格式

1651139627888

2.当请求体格式不同时,需要指定Content-Type的请求头1651139724975

对象格式

<script>
        const xhr = new XMLHttpRequest()
        xhr.open(`post`, `http://www.itcbc.com:3006/api/addbook`)

        const data = {
            bookname: '2从入门到精通2',
            author: '我自己',
            publisher: '黑马出版社',
            appkey:`HZD123`
        }

        // 对象格式的参数 也要设置对应的 conten-type
    
        xhr.setRequestHeader(`Content-type`,`application/json`)
        const str = JSON.stringify(data)
        xhr.send(str) // 传递 a=b&c=d

        xhr.addEventListener(`load`,function(){
            console.log(this.response);
        })
</script>

字符串格式

  <script>
      const xhr = new XMLHttpRequest();
      // open 来指定 请求方式
      xhr.open('post', 'http://www.itcbc.com:3006/api/addbook');
      const data = {
        bookname: '111从入门到精通111',
        author: '我自己',
        publisher: 'hm出版社',
        appkey: 'wanshao1234',
      };
      // 把data 转成 a=b&c=d ....  URLSearchParams 
      const usp=new URLSearchParams(data);
      const query = usp.toString();
      
      // 设置对应的 content-type
      xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
      xhr.send(query); // 传递 a=b&c=d
      
      
      xhr.addEventListener('load', function () {
        console.log(this.response);
      });
    </script>

FormData形式

<script>
    const inp = document.querySelector(`input`)
    const img = document.querySelector(`img`)
    inp.addEventListener(`change`, function () {
        const file = this.files[0]
        const src = URL.createObjectURL(file)
        img.src = src
        
        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>

自封装Ajax

1.根据JQ的Ajax出发,封装属于自己的Ajxa

<script>
    // JQ的代码也是通过封装的 我们跟着这个代码思路自封装
    $.ajax({
            url: `http://www.itcbc.com:3006/api/getbooks`,
            type: `get`,
            data: `appkey=123`,
            success(result) {
                console.log(result);
            }
        })
</script>

总结

1 type 可能是get 也可能是post

2 data 3种(查询字符串 json formdata )

2.实现ajax封装 GET 方式 携带参数

<script>
   const option = {
        url: 'http://www.itcbc.com:3006/api/getbooks',
        type: 'get',
        data: 'appkey=wanshao1234',
        success(result) {
          // result 等于 要等于响应的数据 =  对象格式 
          console.log(result);
        },
      };

      // 我们自己封装一个Ajax函数 来实现ajax上传功能
       ajax(option) // 这是一个函数 调用option里面的属性 实现上传
  
      function ajax(config) {
        const xhr = new XMLHttpRequest();
        xhr.open(config.type, config.url + '?' + config.data);
        xhr.send();
        xhr.addEventListener('load', function () {
          //  响应的数据 this.response
          // console.log(this.response);
          const obj =JSON.parse(this.response)
          config.success(obj)
        });
      }
</script>

3.实现ajax封装 GET方式 不携带参数

   <script>
      // 形参默认值
      // 解构
      // function func(msg="hello") {
      //   console.log(msg);
      // }

      // func();// undefined
      // func();// 输出默认值
      // func('你好'); /// 你好

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

      ajax(option);

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

      function ajax({ url, type, data = '', success }) {
        // 封装的时候考虑到用户 (可能带参数 , 可能不带参数),利用了解构同时设置了默认值
        const xhr = new XMLHttpRequest();
        xhr.open(type, url + '?' + data);
        // 如果 data没有值  url =  http://www.itcbc.com?
        // 如果 data有值  url =  http://www.itcbc.com?appkey=wanshao1234
        xhr.send();
        xhr.addEventListener('load', function () {
          const obj = JSON.parse(this.response);
          success(obj);
        });
      }
    </script>

4.当GET方式中 data是不同类型时

 <body>
    <script>
      // 1.没有参数
      ajax({
        url: 'http://www.itcbc.com:3006/api/getbooks',
        type: 'get',
        // data: 'appkey=wanshao1234',
        success(result) {
          console.log(result);
        },
      });
      // 2.带参数
      ajax({
        url: 'http://www.itcbc.com:3006/api/getbooks',
        type: 'get',
        data: 'appkey=wanshao1234',
        success(result) {
          console.log(result);
        },
      });

      // 3.data是对象格式
      ajax({
        url: 'http://www.itcbc.com:3006/api/getbooks',
        type: 'get',
        data: {
          appkey: 'wanshao1234',
          bookname: '今晚吃啥',
        },
        success(result) {
          console.log(result);
        },
      });

      function ajax({ url, type, data = '', success }) {
        const xhr = new XMLHttpRequest();

        if (typeof data === 'object') {
          // data是一个对象
          data = new URLSearchParams(data).toString();
        }
        // (typeof data === 'object')&&(data = new URLSearchParams(data).toString())
        xhr.open(type, url + '?' + data); // a=1&b=2 URLSearchParams
        xhr.send();
        xhr.addEventListener('load', function () {
          const obj = JSON.parse(this.response);
          success(obj);
        });
      }

      // typeof

      // console.log(typeof "" === 'object');  // 数据是不是对象格式
    </script>
  </body>

5.封装POST 方式

​ 判断当前data数据类型:字符串、对象、FormData(之前内容)

<script>
      ajax({
        url: 'http://www.itcbc.com:3006/api/getbooks',
        type: 'get',
        success(result) {
          console.log(result);
        },
      });
      ajax({
        url: 'http://www.itcbc.com:3006/api/getbooks',
        type: 'post',
        success(result) {
          console.log(result);
        },
      });
    	function ajax({ url, type, data = ``, success }) {
            const xhr = new XMLHttpRequest()
            // 判断请求类型---这里是get请求类型
            if (type === `get`) {
        	// get请求的相关的代码 
                if (typeof data === `object`) {
                    data = (new URLSearchParams(data)).toString()
                }
                xhr.open(type, url + `?` + data)
                xhr.send()
                // post请求类型
            } else if (type === `post`) {
                xhr.open(type, url)
                // 判断是不是字符串
                if (typeof data === `string`) {
				xhr.setRequestHeader(`Content-type`, `application/x-www-form-urlencoded`)
                    xhr.send(data)
                    // 判断是不是对象(普通对象和FormData)
                } else if (typeof data === `object`) {
          // 判断 实例和构造函数的关系 实例 instanceof 构造函数 
                    if (data instanceof FormData) {
       			 // 是 FormData 实例
                        xhr.send(data)
                    } else {
                		// 普通的对象         
                        xhr.setRequestHeader(`Content-type`, `application/json`)
                        const str = JSON.stringify(data)
                        xhr.send(str)
                    }
                }
            }
</script>

   /* 
      判断当前data的数据类型
      1 字符串类型 
              xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
              xhr.send(data); // 传递 a=b&c=d
      2 对象类型
              xhr.setRequestHeader("Content-type","application/json");
              const str =JSON.stringify(data);
              xhr.send(str); // 传递 a=b&c=d
      3 formdata
              xhr.send(formdata);
      
       */
 //  判断当前数据 字符串类型 typeof
     // console.log( typeof data === "string" ); // 字符串类型

      // console.log( typeof data === "object" ); // 对象类型

总结

​ 1.通过今天所学的底层原生Ajax 代码 来封装一个 自己的Ajax上传函数 用JQ的Ajax做参考

​ 2.参照JQ的ajxa代码格式 运用底层的原生Ajax 进行封装使用

​ 3.有传参和不传参两种情况 用默认值+解构思路 进一步优化代码

​ 4.最后把形参.属性名 优化 解构{属性名,data=``(默认值)}

​ 5.data可以是没有参数 可以是字符串 还可以是对象

​ 6.type of 判断是否为对象 运用URLsearcParams/ .toString()转换数据

​ 7.post请求方式 与get不同 所以用if区分 get一部分 post 一部分

​ 8.判断当前data数据类型:字符串、对象、FormData 分别放入相应判断函数内

​ 9.判断字符串类型: typeof 判断实例对应构造函数: 实例 instanceof 构造函数

数据交换格式

概念

数据交换格式,就是服务器端与客户端之间数据传输的格式。

image-20220528165437716

JSON概念

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

image-20220528165544241

JSON数据

用字符串的方式来表示的对象或数组类型的数据,叫做 JSON 数据

JSON 数据的格式有两种:  1、对象格式  2、数组格式

JSON 的语法要求

image-20220528165759187

对象格式的 JSON 数据

image-20220528165902224

数组格式的 JSON 数据

image-20220528165927351

把 JSON 数据转换为 JS 数据

调用浏览器内置的 JSON.parse() 函数,可以把 JSON 格式的字符串转换为 JS 数据,例如:

image-20220528170035605

把 JS 数据转换为 JSON 数据

调用浏览器内置的 JSON.stringify() 函数,可以把 JS 数据转换为 JSON 格式的字符串,例如:

image-20220528170324842

序列化和反序列化

  1. 真实数据转换为字符串的过程,叫做序列化 使用JSON.stringify() 函数进行转换
  2. 字符串转换为真实数据的过程,叫做反序列化 使用 JSON.parse() 函数进行转换

把 XMLHttpRequest 请求到的 JSON 数据反序列化为 JS 对象

在 xhr 对象的 load 事件中,通过 xhr.response 访问到的是 JSON 格式的字符串数据。可以调用 JSON.parse() 函数将 xhr.response 转化为 JS 对象。示例代码如下:

image-20220528171229638

防抖-节流

节流

本质:指的是单位时间内,频繁触发同一个操作,只会触发1次( 上一次的业务没有结束的话 不允许开启下一次业务)

1651193758540

<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>

应用场景1651194406424

使用场景 移动端分页 - 倒计时按钮 等等

防抖

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

1651194332431

<script>
    // 1,定义timeId 
	let timeId
        keyword.addEventListener(`input`, function (e) {
          // 3. 清除之前的延时器
            clearTimeout(timeId)
          // 2. 创建延时器,并记录延时器的ID
            timeId = setTimeout(function () {
                let value = keyword.value.trim()
                let valuePush = `?bookname=${value}`
                getData(valuePush)
            }, 1000)
        })
</script>

应用场景

1651194450397

技术原理

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

​ 2 同时开启一个新的延时器

同源策略&跨域(重点-面试常问)

同源

同源指的是两个URL地址具有相同的协议,主机名(域名),端口号一致

例如:下表给出了相对于 www.test.com/index.html 页面的 5 个同源检测结果

image-20220429094017663

同源策略

同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能。

浏览器的同源策略规定:不允许非同源的 URL 之间进行资源的交互

image-20220429094309881

后台调用后台的资源是可以的,后端会有自己的方式来解决的

浏览器对跨域请求的拦截过程

浏览器允许发起跨域请求,但跨域请求回来的数据,会被浏览器拦截,无法在页面获取到数据

image-20220429135125050

跨域

跨域:不同源就是跨域

出现跨域的根本原因:浏览器的同源策略不允许非同源的 URL进行资源交互

image-20220429095154781

浏览器对跨域的拦截过程

本质:浏览器允许发起跨域请求,当时请求回来会被浏览器拦截,页面无法显示

1651196000477

突破跨域限制方案

JSONP和CORS是两种解决方案

1651196109034

注意:JSONP在实际开发很少用,CORS是主流解决方案

CORS

本质:是解决跨域数据请求的终极解决方案

注意

​ 1.需要浏览器和服务器同时支持下

​ 2.浏览器支持CORS功能(主流浏览器全部支持)

​ 3.服务器开启CORS功能(需要后端为借口开启CORS功能)

image-20220528175046658

CORS 的两个主要优势

1、CORS 是真正的 Ajax 请求,支持 GET、POST、DELETE、PUT、PATCH 等这些常见的 Ajax 请求方式 2、只需要后端开启 CORS 功能即可,前端的代码无须做任何改动

JSONP

JSONP实现跨域数据请求的一种技术解决方案。它只支持 GET 请求,不支持 POST、DELETE 等其它请求。

image-20220528175503898

跨域目的 :拿到后端的数据(前后端跨域 不同源 直接发送Ajax请求失败)

<script>
        function show(option){
            let str = option.message
            console.log(str);
        }
    </script>
<script src="http://www.itcbc.com:3006/api/getscript2"></script>

总结

​ JSONP的底层实现原理: 在底层,用到了 属性!

​ 1.script标签的src属性不受同源策略的影响 跨域

​ 2.浏览器对script的支持:

​ 允许它下载指定路径的JS代码(JS代码 由后端程序员来设定它的内容)

​ show({data:["a","b"]})=>show是后端命名的 show中传递了真正的数据

​ 而且还会执行JS代码

​ 前端需要自己来定义 show方法的内容 指我前端的业务逻辑