08-Ajax

服务器相关概念

1. 客户端与服务器

服务器 : 上网过程中,负责 存放或对外提供资源 的电脑,叫做服务器

客户端 : 在上网过程中,负责 获取和消费资源 的电脑,叫做客户端

2. URL地址的概念&组成⭐️

1.URL的概念

URL(全称是 UniformResourceLocator) 中文叫 统一资源定位符,用于标识互联网上每个资源的唯一存放位置。浏览器只有通过URL地址,才能正确定位资源的存放位置,从而成功访问到对应的资源

2. URL的组成

URL地址一般由三部分组成:

协议 , 主机名 , 端口号 , 路径

  • 客户端与服务器之间的 通信协议
  • 存有该资源的 服务器名称(主机名)
  • 端口号0-65535之间的整数 , 主要作用表示一台计算机中的特定进程所提供的服务(通过端口号 , 访问百度下的 ,网站A,网站B)
  • 资源在服务器上 具体的存放位置(请求路径)
08-Ajax_第1张图片

端口号

端口号 80 可以省略不写

08-Ajax_第2张图片

3. 客户端与服务器通信过程

客户端与服务器之间的通讯过程,分为: 请求-处理-响应 三个步骤

image-20220214100513883

4. 资源的请求方式

客户端请求服务器时,请求的方式 有很多种,最常见的两种请求方式分别是 getpost 请求

  • get 请求,通常用于 获取服务器资源(要资源)

例如:根据 URL 地址,从服务器获取 HTML文件、css文件、js文件、图片文件、数据资源等。

  • post 请求,通常用于 向服务器提交数据(送资源)

例如:登录时,向服务器 提交登录信息、注册时向服务器 提交注册信息、添加用户时向服务器 提交用户信息等各种 数据提交操作

5. 网页中如何请求数据

(1)通过地址栏发送请求

(2)通过表单发送请求

(3)通过ajax对象发送请求

image-20220214142551556

了解Ajax

什么是Ajax

Ajax 的全称是 Asynchronous JavaScript And XML(异步 JavaScriptxml

通俗理解:在网页中利用 XMLHttpRequest (是DOM 内置的一个API )对象和服务器进行数据交互的方式,就是Ajax

之前所学的技术,只能把网页做的更美观漂亮 ,或添加一些动画效果,但还是,Ajax能让我们轻松实现 网页服务器之间的 数据交互

08-Ajax_第3张图片

Ajax应该用场景

场景一:用户名检测 : 检测用户名是否被占用

场景二:搜索提示 : 动态 加载搜索提示列表

场景三:数据无刷新分页显示 : 根据页码值动态刷新表格的数据

场景四:数据的无刷新增删改查 : 数据的添加、删除、修改、查询操作

jQuery中的Ajax

image-20220214103107360

浏览器中提供的 XMLHttpRequest 用法比较复杂,所以 jQueryXMLHttpRequest 进行了封装,提供了一系列Ajax相关的函数,极大地 降低了Ajax的使用难度

08-Ajax_第4张图片

jQuery中发起 Ajax 请求最常用的三个方法如下:

  • $.get() get方式请求,用于**获取(下载)**数据
  • $.post() post方式请求,用于提交(上传)数据
  • $.ajax() 比较综合,既可以获取数据,又可以提交数据**(获取&提交)**

url 地址错误

image-20220214104830201

$.get() 函数介绍

用于**获取(下载)**数据

get 请求,从而将服务器上的资源请求到客户端来进行使用

$.get(url,[data],[callback]) []:可选参数
08-Ajax_第5张图片
  • $.get()发起不带参数的请求

**使用 $.get() 函数 发起不带参数的请求时,直接提供给 **请求的 URL 地址请求成功之后的回调函数 即可

      $(function () {
        $.get("http://www.liulongbin.top:3006/api/getbooks", function (res) {
          console.log(res);
        });
      });
  • $.get()发起携带参数的请求

使用$.get() 发起携带参数的请求,那么携带的参数应该写在第二个参数的位置

      $(function () {
        $.get("http://www.liulongbin.top:3006/api/getbooks", { bookname: "三国演义", author: "罗贯中" }, function (res) {
          console.log(res);
        });
      });
08-Ajax_第6张图片

image-20220215094450682

$.post() 向服务器提交数据

用于提交(上传)数据

      $(function () {
        $("button").on("click", function () {
          $.post(
            "http://www.liulongbin.top:3006/api/addbook",
            {
              bookname: "啊飞的一天",
              author: "阿飞",
              publisher: "黑马",
            },
            function (res) { // 成功后的回调函数
              console.log(res);
            }
          );
        });
      });

$.ajax() 函数介绍

$.ajax() 注意事件

08-Ajax_第7张图片
  • get : 请求方式
  • url : 数据的接口
  • data : 数据
  • success : 成后返回的值
$.ajax()发起 get 请求

只需要将 type 属性 的值设置为 ‘GET’ 即可

        // ajax-不带参数请求
        $("#btn1").on("click", function () {
          $.ajax({
            type: "get",
            url: "http://www.liulongbin.top:3006/api/getbooks",
            data: {},
            success: function (res) {
              console.log(res);
            },
          });
        });

        // -----------------------------

        // ajax - 携带参数请求;
        $("#btn2").on("click", function () {
          console.log(11);
          $.ajax({
            type: "get",
            url: "http://www.liulongbin.top:3006/api/getbooks",
            data: { bookname: "三国演义" },
            success: function (res) {
              console.log(res);
            },
          });
        });

$.ajax 发起 post 请求

只需要把 type属性的值 设置为 ‘post’ 即可

 // ajax-post请求
        $("#btn3").on("click", function () {
          $.ajax({
            type: "post",
            url: "http://www.liulongbin.top:3006/api/addbook",
            data: {
              bookname: "程序员自我修养",
              author: "阿飞",
              publisher: "黑马",
            },
            success: function (res) {
              console.log(res);
            },
          });
        });
      });

接口

image-20220214143526937

1. 接口的概念

使用 Ajax 请求数据时,被请求的 URL 地址,就叫做 数据接口(简称接口)。同时,每个接口必须有请求方式。

例如:

http://www.liulongbin.top:3006/api/getbooks 获取图书列表的接口(get请求)
http://www.liulongbin.top:3006/api/addbook  添加图书的接口(post请求)

2. 接口的请求过程

GET方式请求接口的过程
08-Ajax_第8张图片
POST方式请求接口的过程
08-Ajax_第9张图片

3. 接口文档

ajax课程的在线接口文档:https://www.showdoc.com.cn/ajaxapi?page_id=3753323218792173

接口的说明文档它是我们调用接口的依据。好的接口文档包含了对 接口URL参数 以及 输出内容 的说明,我们参照接口文档就能方便的知道接口的作用,以及接口如何进行调用

接口文档的组成部分
  1. **接口名称:**用来标识各个接口的简单说明,如 登录接口获取图书列表接口
  2. **接口URL:**接口的调用地址
  3. **调用方式:**接口的调用方式,如 GET 或者 POST
  4. **参数格式:**接口需要传递的参数,每个参数必须包含 参数名称参数类型是否必选参数说明 这4项内容
  5. 响应格式:接口的返回值的详细描述,一般包含数据名称数据类型说明3项内容
  6. **返回示例(可选):**通过对象的形式,列举服务器返回数据的结构
接口文档示例
  • 参数格式
08-Ajax_第10张图片
  • 响应格式
08-Ajax_第11张图片
  • 返回示例
08-Ajax_第12张图片

4. 接口测试工具

1. 什么是接口测试工具

为了验证接口是否被正常被访问,我们常常需要使用接口测试工具,来对数据接口进行检测

**好处:**接口测试工具能让我们在 不写任何代码 的情况下,对接口进行 调用测试

常用的就是:PostMan

2. 了解 Postman 界面结构
08-Ajax_第13张图片
3. 使用PostMan测试GET接口

image-20220214143749786

4. 使用PostMan测试POST接口
08-Ajax_第14张图片
5. 错误提示

url 地址错误

image-20220214104830201

Cannot GET/api/addbook 请求地址 , 请求方式错误

image-20220214145600434

两个案例

图书管理

UI界面搭建

需要使用到的库和插件

  • 用到的 cssbootstrap.css
  • 用到的 javascriptjquery.js
  • 用到 vs code 插件 Bootstrap 3 Snippets

08-Ajax_第15张图片

搭建步骤

  • Panel面板搭建
    • 创建panel板 (快捷键:bs3-panel:primary
    • panel-body 里面,创建3个对应的输入框 (快捷键:bs3-input:addon:text),对应修改标题
    • panel-body 最后面,创建 button按钮 (快捷键:bs3-button:primary),修改内容
  • 图书的表格
    • 创建 table(快捷键:bs3-table:bordered
    • 在里面创建对应5个td,填写里面内容

内联表单

元素添加 .form-inline 类可使其内容左对齐并且表现为 inline-block 级别的控件。

image-20220215102459976
1. 获取渲染图书列表数据

ajax课程的在线接口文档:https://www.showdoc.com.cn/ajaxapi?page_id=3753323218792173

步骤:

  • 查阅资料中的接口文档,找到获取图书列表的接口
  • 定义 script 标签,创建入口函数
  • 利用 $.get() 方法,传入相应的url,和成功之后的回调函数
  • 在回调函数中获取到请求成功的数据
        // [1] 渲染列表
        getBookList();
        function getBookList() {
          // (1)调接口,获取所有的图书馆数据
          $.ajax({
            type: "get",
            url: "http://www.liulongbin.top:3006/api/getbooks",
            success: function (res) {
              // (2) 判断数据是否获取成功
              if (res.status !== 200) {
                return alert("获取图书失败");
              }
              //  (3) 把数据遍历渲染到页面
              //  遍历数据,生成tr
              var rows = [];
              res.data.forEach(function (item, index, array) {
                var newStr = `
     
        ${item.id}
        ${item.bookname}
        ${item.author}
        ${item.publisher}
        ${item.id}>删除
      `;
                //   把遍历出来的数据 追加到空数组里
                rows.push(newStr);
              });
              // 添加到tbody中
              //   性能优化去掉字符串拼接
              $("tbody").html(rows.join(""));
            },
          });
        }
2. 删除功能实现
  • 利用 tbody 容器,通过事件委派的方式,给动态创建的a标签绑定事件
  • 删除图书需要通过id删除,所以我们需要得到对应的id,我们利用自定义属性的方式,传递过来相应的id
        // [2] 删除功能
        // (1) 给删除按钮绑定单击事件 (事件委托,动态检测)
        // (2) 获取被删图书的 id
        //   1) 渲染列表时,给删除添加自定义属性 data-id
        //   2) 获取自定义属性的值 $(this).attr(data-id)
        // (3) 询问是确定删除 if(confirm) // true false
        // (4) 调接口
        // (5) 判断是否删除成功,成功后重新渲染列表
        $("tbody").on("click", ".del", function () {
          var id = $(this).attr("data-id"); // 获取自定义属性的值
          if (confirm("确定要删除")) {
            $.ajax({
              type: "get",
              url: "http://www.liulongbin.top:3006/api/delbook",
              data: { id: id },
              success: function (res) {
                if (res.status !== 200) {
                  return alert(res.msg);
                }
                getBookList();
              },
            });
          }
        });
3. 添加功能实现
        // [3] 添加功能
        // (1) 给添加按钮绑定单击事件
        // (2) 收集数据
        // (3) 判断数据是否合法(不能为空)
        // (4) 调接口 ,添加图书
        // (5) 判断是否添加成功 , 如果成功重新渲染页面
        $("#btnAdd").on("click", function () {
          var bookname = $("#iptBookname").val().trim();
          var author = $("#iptAuthor").val().trim();
          var publisher = $("#iptPublisher").val().trim();
          if (bookname === "" || author === "" || publisher === "") {
            return alert("值不能为空");
          }            
          // if (bookname.leng <= 0 || author.length <= 0 || publisher.length <= 0) {
            return alert("值不能为空");
          }
          $.ajax({
            type: "post",
            url: "http://www.liulongbin.top:3006/api/addbook",
            data: {
              bookname: bookname,
              author: author,
              publisher: publisher,
            },
            success: function (res) {
              if (res.status !== 201) {
                return alert(res.msg);
              }
              getBookList();
              $("#iptBookname").val("");
              $("#iptAuthor").val("");
              $("#iptPublisher").val("");
            },
          });
        });
  • 每次发送完请求 , 返回的请求先要判断一下是否成功 , 再重新调用下数据

聊天机器人

实现功能点
  • 梳理案例代码结构
  • 将用户输入的内容渲染到聊天窗口
  • 发起请求获取聊天消息
  • 将机器人的聊天内容转为语音
  • 通过 播放语音
  • 使用回车发送消息
梳理案例的代码结构
  • UI结构梳理

  • 业务代码抽离

  • resetui() 函数作用-让聊天框区域自动滚动到底部

1. 将用户输入的内容渲染到聊天窗口

ajax课程的在线接口文档:https://www.showdoc.com.cn/ajaxapi?page_id=3753323218792173

  • 为发送按钮绑定点击事件
  • 在点击事件函数里面判断一下用户输入内容是否为空,注意:如果为空,我们清除一下输入框内容
  • 获取到对应的ul容器,调用 append 函数来追加 li,注意:追加li的类名叫做 right_word
  • 清除文本输入框的值
  • 最后调用一下 resetui(),让聊天框区域自动滚动到底部
  // [1] 单击发送 , 把聊天消息渲染到页面
  $("#btnSend").on("click", function () {
    var text = $("#ipt").val().trim(); // 1.获取输入框的信息
    console.log(text);
    // 判断输入框是否为空 // if (text==="") 
    // if (!text) return;
    if (text.length <= 0) {
      return;
    }
    // 2.信息渲染到页面
    // 新建li
    var newLi = `
      
  • ${text}
  • `
    ; $("#talk_list").append(newLi); resetui(); // 滚动条滚动到最新位置 $("#ipt").val(""); // 清空输入框 //[2] 向机器人发送消息(调接口),机器人回复 getMsg(text); });
    2. 发起请求获取聊天信息
    • 定义一个函数 getMsg() 接收一个参数,参数就是用户发送的信息
    • 利用 $.ajax() 发送一个 GET 方式请求,传入请求地址 http://www.escook.cn:3006/api/robot
    • 定义请求数据 spoken:value
    • 定义success成功的回调,在回调函数里面判断返回数据的 message 是否等于 success
    • 给容器动态添加返回的内容
      // [2]封装一个函数 专门向机器人发送消息,渲染回复语
      // 1.把输入框内容发送给机器人
      function getMsg(text) {
        $.ajax({
          type: "get",
          url: "http://www.liulongbin.top:3006/api/robot",
          data: { spoken: text },
          success: function (res) {
            console.log(res);
            if (res.message == "success") {
              console.log("机器人回复了", res.data.info.text);
              // 把机器人的回复,渲染到页面
              // 新建对话框 li
              var newLi = `
                  
  • ${res.data.info.text}
  • `
    ; $("#talk_list").append(newLi); resetui(); // 滚动条滚动最新位置 getVoice(res.data.info.text); // [3] 把机器人的文字消息转成语音 } }, }); }
    3. 将机器人聊天内容转成语音
    • 封装函数 getVoice() 接收一个参数,机器人的聊天信息

    • 利用 $.ajax() 发送一个 GET 方式请求,传入请求地址 http://ajax.frontend.itheima.net:3006/api/synthesize

    • 定义请求数据 text:value

    • 定义success成功的回调,判断返回的状态码是否是200,如果是代表成功

    • 在页面上定义 audio 标签,设置隐藏,等数据返回之后,利用这个 audio 来进行播放。设置 autoplay 属性来进行自动播放

    • 结构里面加一个音频标签把获取到的src地址赋值进去播自动放音频

    
      <audio src="" id="voice" autoplay style="display: none;">audio>
    
      // 2.封装一个函数,专门把机器人回复的文字转成语音
      function getVoice(text) {
        // 调接口
        $.ajax({
          text: "get",
          url: "http://www.liulongbin.top:3006/api/synthesize",
          data: { text: text },
          success: function (res) {
            console.log(res);
            if (res.status === 200) {
              // console.log(res.voiceUrl)
              // 给音频标签设置src
              $("#voice").attr("src", res.voiceUrl);
            }
          },
        });
      }
    
    4. 通过回车键发送消息
    • 给文本输入框注册 keyup 事件,按键弹起的事件监听
    • 在事件函数里面,通过keycode 来获取对应的按键的 机器码
    • 判断 keycode 是否等于 13(不需要去记忆,开发时候打印调试一下就行了),如果是,代表是回车键
    • 如果是回车键,模拟用户点击: $('#btnSend').click()
      // [4]在输入框中敲回车,就能发送消息
      // 为输入框框绑定 keyup 事件
      $("#ipt").on("keyup", function (e) {
        // 判断键值
        if (e.keyCode === 13) {
          // 触发“发送”按钮的click事件
          $("#btnSend").click();
        }
      });
    

    Form表单的基本使用

    表单在网页中主要负责 数据采集功能 并把采集的信息提交到服务器端进行处理

    表单的组成部分

    • 表单标签
    • 表单域:包含了文本框,密码框,隐藏域,都行文本框,复选框,单选框,下拉选择框和文件上传框等等
    • 表单按钮:通过设置type属性为submit来触发form表单的提交 , 通过设置属性 值为 reset来重置表单
    08-Ajax_第16张图片

    标签的属性(⭐⭐⭐)

    action
    • action 属性用来规定当提交表单时,向何处发送表单数据
    • 表单在没有设置 action 属性或 action值为空下,action默认值为当前页面的 URL 地址

    注意: 当提交表单后,会立即跳转到 action 属性指定的 URL 地址

    target
    • target 属性用来规定 在何处打开 action URL
    • _blank 在新窗口打开
    • _self 在相同窗口打开
    • 默认情况下,target的值是 _self,表示在相同的框架中打开 action URL
    08-Ajax_第17张图片
    method
    image-20220217101705298

    method 属性用来规定 以何种提交方式 把表单数据提交到 action URL

    它的可选值有两个,分别是 getpost

    默认情况下,method的值为 get, 表示通过URL地址的形式,把表单数据提交到 action URL

    注意:

    • get 方式适合用来提交少量的简单的数据 , 最多提交1024字节的数据 , 放到 url 地址后面
    • post 方式适合用来提交大量的复杂的,或包含文件上传的数据 (安全性高) , 数据放在用户看不到的地方 , 提交数据没有限制
    enctype

    enctype属性用来规定在 发送表单数据之前如何对数据进行编码

    注意:
    在涉及到文件上传的操作时,必须将 enctype 的值设置为 multipart/form-data表单的同步提交及缺点

    表单的同步提交及缺点

    什么是表单的同步提交

    通过点击 submit 按钮,触发表单提交的操作,从而使页面跳转到 action URL 的行为,叫做表单的同步提交

    表单同步提交的缺点
    • 表单同步提交后,整个页面会发生跳转,跳转到 action URL 所指向的地址,用户体验很差
    • 表单同步提交后,页面之前的状态和数据会丢失

    解决方案

    表单只复杂采集数据,Ajax负责将数据提交到服务器

    通过Ajax提交表单数据

    1. 监听表单提交事件

    • $("#form").submit(function () {}

    jQuery 中,可以使用如下两种方式,监听到表单的提交事件 submit , 会跳转页面

    08-Ajax_第18张图片
          $("#form").submit(function () {
            alert(1);
          });
    
          $("#form").on("submit", function () {
            alert(1);
          });
    

    2. 阻止表单默认提交行为(⭐⭐⭐)

    • e.preventDefault()
          $("#form").submit(function (e) {
            e.preventDefault();
          });
    
          $("#form").on("submit", function (e) {
            e.preventDefault();
          });
    

    3. 如何快速获取表单数据(⭐⭐⭐)

    08-Ajax_第19张图片

    serialize() 函数

    serialize() 函数的好处:可以一次性获取到表单中的所有的数据。键值对字符串

    注意: 一定要给表单设置 name 属性 , 否则收集不到数据

    $("#form").serialize();
    
    08-Ajax_第20张图片

    具体实现步骤

    image-20220217111016493

          $("#form").submit(function (e) {
            e.preventDefault();
            var data = $(this).serialize();
            
            console.log(data);
            $.ajax({
              method: "post",
              url: "http://www.liulongbin.top:3006/api/addbook",
              data: data,
              success: function (res) {
                console.log(res);
              },
            });
          });
    

    4. 使用ajax向服务器发送请求

    案例-评论列表

    使用到的技术方案[ form + ajax ]

    UI结构搭建

    步骤

    • 评论面板结构
      • 创建panel (快捷键:bs3-panel:primary
      • 修改title里面的标题
      • 在body 里面 创建两个输入框,加上对应的文本提示
      • 最下面加上一个 button(快捷键:bs3-button:primary
    • 评论列表结构
      • 构建一个list列表(快捷键:bs3-list-group
      • 在第一个li里面放两个 span,写入 评论时间评论人

    1. 获取评论列表数据

    • 定义函数来获取评论列表数据 getCommentList()
    • 查阅接口文档,关注请求url,是否需要携带参数,请求方式
    • 利用 $.ajax() 来进行请求
    • success 回调函数中,判断请求数据是否成功,如果状态码不是200,提示用户
      getCommentList();
      // [1] 获取评论 ,渲染页面
      function getCommentList() {
        // 发送 ajax 请求 获取数据
        $.ajax({
          url: "http://www.liulongbin.top:3006/api/cmtlist",
          success: function (res) {
            console.log(res);
            // 判断请求是否成功
            if (res.status !== 200) alert("获取失败");
    
            // 渲染数据到页面
          },
        });
    

    2. 渲染评论列表

    • 创建一个空数组(rows),用来存放每一个元素的html字符串结构
    • 遍历服务器返回的数据,每遍历一次,拼接一个对应的html字符串结构,然后放入到数组中
    • 找到list容器,先清空一下里面内容,然后利用 append 添加新的数据
            // 渲染数据到页面
            var rows = [];
            res.data.forEach((item) => {
              var newLi = `
           
  • 评论时间:${item.username} 评论人:${item.time} ${item.content}
  • `
    ; rows.push(newLi); }); $("#cmt-list").html(rows.join("")); },

    3. 完成发表功能

    改造form表单
    • 把之前panel-body的标签改成 form 标签
    • 给每一个输入框设置 name 属性,name属性的值最好与接口文档定义的参数名称一致
    • 注册 sumbit 事件,阻止表单提交的默认行为
    • 获取用户输入内容(利用 serialize()

    示例代码

    $(function () {
      $('#formAddCmt').submit(function (e) {
        e.preventDefault(); // 阻止默认行为
        var data = $(this).serialize(); // 收集表单数据
        })
      })
    })
    
    完成发表功能
    • 查阅接口文档
    • 利用 $.post() 发送请求,传入数据
    • 在成功回调函数里面判断 返回的 status 是否是201,如果是代表成功,失败进行提示
    • 刷新页面(调用 getCommentList()),清空表单内容($('#formAddCmt')[0].reset()

    示例代码

    • 表单里数据的重置方法 reset()
    • document.forms[0].restet()
    $("#myForm")[0].reset() 方法可把表单中的元素重置为它们的默认值
    
      // [2] 发表评论
      $("#formAddCmt").submit(function (e) {
        e.preventDefault(); // 阻止默认行为
        var data = $(this).serialize(); // 收集表单数据
        // ajax 发送请求
        $.ajax({
          method: "post",
          url: "http://www.liulongbin.top:3006/api/addcmt",
          data: data,
          success: function (res) {
            console.log(res);
            if (res.status !== 201) return "添加失败";
            getCommentList(); // 重新渲染页面
            // document.querySelector("#formAddCmt").reset();
            $("#formAddCmt")[0].reset();
          },
        });
      });
    

    模板引擎

    相关概念

    之前在渲染UI结构时候,拼接字符串是比较麻烦的,而且很容易出现问题

    模板引擎,它可以根据程序员指定的 模板结构数据,自动生成一个完整的HTML页面

    08-Ajax_第21张图片

    模板引擎的好处

    • 减少了字符串的拼接操作
    • 使代码结构更清晰
    • 使代码更易于阅读与维护

    art-template模板引擎

    简介

    art-template 是一个简约,超快的模板引擎,中文官首页:http://aui.github.io/art-template/zh-cn/index.html

    安装(⭐⭐⭐)

    • 浏览器访问 http://aui.github.io/art-template/zh-cn/docs/installation.html
    • 找到 安装 导航栏,找到下载链接,右键下载即可
    08-Ajax_第22张图片

    基本使用(⭐⭐⭐)

    08-Ajax_第23张图片

    art-template的使用步骤

    ① 导入 art-template
    ② 定义数据
    ③ 定义模板
    ④ 调用 template 函数
    ⑤ 渲染HTML结构

    • 导入 art-template

      • 在window全局,就多了一个函数,叫做 template(‘模板id’,需要渲染的数据对象)
      <script src="./lib/template-web.js"></script>
      
    • 定义数据

      var data = { name: 'zs', age: 20}
      
    • 定义模板

      • 模板的 HTML 结构,必须定义到 script 标签中,注意:需要把type属性改成 text/html
      • 给 模板 添加一个 id
      • 模板里面如果需要使用到传入的数据,利用 {{}} 来实现,例如:{{name}},那么就会去找 我们调用 template() 函数 第二个参数里面对应的name属性的值
      <script type="text/html" id="tpl-user">
          <h1>{{name}}    ------    {{age}}</h1>
      script>
      
    • 调用 template 函数 , 自动生成 html 字符串

      • 函数的返回值就是拼接好的模板字符串
      var htmlStr = template('tpl-user', res)
      
    • 渲染HTML结构

      • 最后我们需要把template返回的模板字符串设置到页面容器中
      $('#container').html(htmlStr)
      

    代码示例

    {{ }} 占位

    {{each 数组}}
    {{$value}}
    {{/each}}
    
        <!-- 3.定义模版 -->
        <script type="text/html" id="tpl">
          <p>{{ name }}</p>
          <p>{{ dog.color }}</p>
          <p>{{ age > 18 ? "成年" : "未成年"}}</p>
          <p>{{ age-3 }}</p>
          <div>{{@ title}}</div>
        </script>
    
        <script src="./lib/jquery.js"></script>
        <!-- 1.导入 art-template -->
        <script src="./lib/template-web.js"></script>
        <script>
          // 2.定义数据
          var data = {
            name: "zs",
            age: 19,
            title: "

    我是h1标签

    "
    , dog: { color: "red", }, }; // 3.调用模版 var htmlStr = template("tpl", data); console.log(htmlStr); // 4.渲染HTML结构 $("#box").html(htmlStr);

    标准语法

    1. 什么是标准语法

    art-template 提供了 {{}} 这种语法格式,在 {{}} 内可以进行 变量输出循环数组 等操作,这种 {{}} 语法在 art-template 中被称为标准语法(模板语法)

    2. 标准语法 - 输出
    {{value}}
    {{obj.key}}
    {{obj['key']}}
    {{a ? b : c}}
    {{a || b}}
    {{a + b}}
    

    在 {{ }} 语法中,可以进行变量的输出、对象属性的输出、三元表达式输出、逻辑或输出、加减乘除等表达式输出。

    3. 标准语法 – 原文输出
    {{@ value }}
    

    如果要输出的 value 值中,包含了 HTML 标签结构,则需要使用原文输出语法,才能保证 HTML 标签被正常渲染。

    4. 标准语法 – 条件输出
    {{if value}} 按需输出的内容 {{/if}}
    {{if v1}} 按需输出的内容 {{else if v2}} 按需输出的内容 {{/if}}
    

    如果要实现条件输出,则可以在 {{ }} 中使用 if … else if … /if 的方式,进行按需输出。

    5. 标准语法 – 循环输出
    {{each arr}}
     {{$index}} {{$value}}
    {{/each}}
    

    如果要实现循环输出,则可以在 {{ }} 内,通过 each 语法循环数组,当前循环的索引使用 $index 进行访问,当前的循环项使
    用 $value 进行访问。

    6. 标准语法 – 过滤器

    过滤器的本质,就是一个 function 处理函数。

    渲染一个变量的值 , 处理变量的格式

    语法

    {{$value.time|dateFormat}}
    

    过滤器语法类似于 管道操作符,它的上一个输出作为下一个输入 , 把 {{$value}.time} (需要处理的值)传给过滤函数

    定义过滤器的基本语法如下:

    template.defaults.imports.dateFormat = function (val){/*return处理的结果*/}
    
    • 格式化格式化日期
    • 定义大小写
    // 在模板引擎中使用过滤器
    <h2>{{msg|toUp}}</h2>
    // 定义大小写函数
          template.defaults.imports.toUp = function (val) {
            return val.toUpperCase();
          };
    

    image-20220217163654813

    定义格式化日期时间的过滤器函数

    • 定义数据

      var data = { regTime: new Date() }
      
    • 定义过滤器

          // 定义格式化日期时间的过滤器函数
          template.defaults.imports.dateFormat = function (val) {
            var dt = new Date(val);
    
            var y = dt.getFullYear();
            var m = dt.getMonth() + 1;
            m = padZero(m);
            var d = dt.getDate();
            d = padZero(d);
    
            var hh = dt.getHours();
            hh = padZero(hh);
            var mm = dt.getMinutes();
            mm = padZero(mm);
            var ss = dt.getSeconds();
            ss = padZero(ss);
    
            return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
          };
          // 定义补零函数
          function padZero(n) {
            return n < 10 ? `0${n}` : n;
          }
    
    • 在模板引擎中使用过滤器

        <script type="text/html" id="tpl-user">
          <h3>{{regTime | dateFormat}}</h3>
        script>
      

    案例-新闻列表

    定义新闻列表item模板

    • 创建 script 标签,更改type属性值为 text/html,给模板定义id
    • 找到静态页面中 item 的结构,拷贝到模板里面

    编译模板渲染结构

    art-template的使用步骤

    ① 导入 art-template
    ② 定义数据
    ③ 定义模板
    ④ 调用 template 函数
    ⑤ 渲染HTML结构

    模板代码

        <div id="news-list"></div>
    
        <!-- 定义模板 -->
        <script type="text/html" id="tpl">
          {{each data}}
          <div class="news-item">
            <img class="thumb" src="{{'http://www.liulongbin.top:3006'+$value.img}} " alt="" />
            <div class="right-box">
              <h1 class="title">{{$value.title}}</h1>
              <div class="tags">
                {{each $value.tags.split(",")}}
                <span>{{$value}}</span>
                {{/each}}
              </div>
              <div class="footer">
                <div>
                  <span>胡润百富</span>&nbsp;&nbsp;
                  <span> {{$value.time|dateFormat}} </span>
                </div>
                <span> {{ $value.cmtcount }} </span>
              </div>
            </div>
          </div>
          {{/each}}
        </script>
    

    js代码

      // [1] 获取新闻数据渲染到页面
      getNewsList();
      function getNewsList() {
        // 发送ajax 请求,获取数据
        $.ajax({
          url: "http://www.liulongbin.top:3006/api/news",
          success: function (res) {
            console.log(res);
            // 判断请求是否成功
            if (res.status !== 200) return "获取数据失败";
    
            // [2]渲染到页面
            // 1.引入js
            // 2.准备数据
            // 3.准备模版
            // 4.调用templat
            var htmlStr = template("tpl", res); // res 对象
            // 5.渲染数据到页面
            $("#news-list").html(htmlStr);
          },
        });
      }
    
      // 定义格式化日期时间的过滤器函数
      template.defaults.imports.dateFormat = function (val) {
        var dt = new Date(val);
    
        var y = dt.getFullYear();
        var m = dt.getMonth() + 1;
        m = padZero(m);
        var d = dt.getDate();
        d = padZero(d);
    
        var hh = dt.getHours();
        hh = padZero(hh);
        var mm = dt.getMinutes();
        mm = padZero(mm);
        var ss = dt.getSeconds();
        ss = padZero(ss);
    
        return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
      };
      // 定义补零函数
      function padZero(n) {
        return n < 10 ? "0" + n : n;
      }
    

    图书管理-模版引擎

    创建模版

        <!-- 模版引擎 -->
        <script type="text/html" id="tpl">
          {{each data}}
          <tr>
            <td>{{$value.id}}</td>
            <td>{{$value.bookname}}</td>
            <td>{{$value.author}}</td>
            <td>{{$value.publisher}}</td>
            <td><a href="javascript:;" class="del" data-id="{{$value.id}}">删除</a></td>
          </tr>
          {{/each}}
        </script>
    

    渲染数据到表格

            // [1]渲染数据到表格
            getBookList();
            function getBookList() {
              $.ajax({
                type: "get",
                url: "http://www.liulongbin.top:3006/api/getbooks",
                success: function (res) {
                  console.log(res);
                  if (res.status !== 200) {
                    return alert("图书获取失败");
                  }
    
                  var htmlStr = template("tpl", res); // 4.调用template函数
                  // console.log(htmlStr)
                  $("#tb").html(htmlStr); // 5.渲染数据到页面
                },
              });
            }
    

    用 form 添加数据

    注意 : data 选项的值有两种 ⭐️⭐️⭐️

    1. 对象 , (对象的属性名必须和接口文档的参数名保持一致 )
      • data:{bookname:“三国演义” , author: “罗贯中”}
    2. 键值对字符串(“参数名=值&参数名=值”)
      • data : " bookname = 三国演义 & author = 罗贯中 "
            $("#Form").on("submit", function (e) {
              e.preventDefault(); // 阻止默认行为
              var data = $(this).serialize(); // 获取表单数据
              console.log(data);
              // if ($("#Bookname").val().length <= 0 || $("#Author").val().length <= 0 || $("#Publisher").val().length <= 0)
              //   return alert("不能为空");
    
              var dataArr = data.split("&"); // 截取成数组
              for (var i = 0; i < dataArr.length; i++) {
                var Karr = dataArr[i].split("="); // 数组在继续分割
                if (karr[1] === "null" || Karr[1] === "") {
                  return alert("值不能为空");
                }
              }
    
              // ajax 发送请求
              $.ajax({
                method: "post",
                url: "http://www.liulongbin.top:3006/api/addbook",
                data: data, // 可以是对象,可以是键值对
                success: function (res) {
                  // console.log(res);
                  if (res.status !== 201) {
                    return alert("添加失败");
                  }
                  getBookList(); // 渲染
                  $("#Form")[0].reset(); // 清空
                },
              });
            });
    

    作用 : 指定的字符串中进行正则搜索

    模板引擎的实现原理

    正则与字符串操作

    exec函数

    exec() 函数用于 检索字符串 中的正在表达式的匹配

    如果字符串中有匹配的值,则返回该匹配值,否则返回 null

    示例代码如下:

    08-Ajax_第24张图片

    分组

    正则表达式中 () 包起来的内容表示一个分组,可以通过分组来 提取自己想要的内容,示例代码如下

    字符串的 replace 函数

    replace() 函数用于在字符串中 用一些字符 替换 另一些字符的

    08-Ajax_第25张图片
    多次replace
    08-Ajax_第26张图片
    使用循环来replace
    08-Ajax_第27张图片

    替换真实的内容

    08-Ajax_第28张图片

    实现简易的模板引擎

    • 定义模板结构

      08-Ajax_第29张图片

    • 预调用模板引擎

    • 封装 template 函数

      08-Ajax_第30张图片

    • 导入并使用自定义的模板引擎


    XMLHttpRequest的基本使用

    使用xhr发起GET请求

    步骤

    • 创建 xhr 对象 new
    • 调用 xhr.open() 函数 , 设置请求方式和地址
    • 调用 xhr.send() 函数 , 发送请求
    • 监听 xhr.onreadystatechange 事件
          // 1.创建 ajax 对象
          var xhr = new XMLHttpRequest();
          // 2.设置请求方式和地址
          xhr.open("get", "http://www.liulongbin.top:3006/api/getbooks");
          // 3.发送请求
          xhr.send();
          // 4.监听onreadystatechange 事件(设置服务响应后执行的函数)
          xhr.onreadystatechange = function () {
            // 判断请求是否完成
            // readyState 表示当前ajax 请求处于什么阶段 , 4表明请求完成阶段
            // status响应转态码
            if (xhr.readyState == 4 && xhr.status == 200) {
              // 获取服务器响应的数据---json字符串
              console.log(xhr.responseText);
              // join 字符串转转对象
              var data = JSON.parse(xhr.responseText);
              console.log(data);
            }
          };
    

    请求转态和响应转态

    08-Ajax_第31张图片

    xhr对象的readyState属性

    XMLHttpRequest 对象的 readyState 属性,用来表示当前 Ajax 请求所处的状态。每个 Ajax 请求必然处于以

    08-Ajax_第32张图片

    使用xhr发起带参数的GET请求

    这种在 URL 地址后面拼接的参数,叫做查询字符串。所有get请求的参数格式都是查询字符串

          $.get('http://www.liulongbin.top:3006/api/getbooks', { bookname: '三国演义', author: '罗贯中' }, function(res) {
           console.log(res)
     })
    

    get请求参数的要求:

    • 位置: url地址?的后面
    • 格式 : (查询字符串):键值对字符串—'参数名=值&参数名=值
    var xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks?id=1')
    xhr.send()
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4 && xhr.status === 200) {
         console.log(xhr.responseText)
      }
    }
    

    查询字符串

    URL 编码: 就是使用英文字符去代替汉字等

    **定义:**查询字符串(URL 参数)是指在 URL 的末尾加上用于向服务器发送信息的字符串(变量)。

    **格式:**将英文的 ? 放在URL 的末尾,然后再加上 参数=值 ,想加上多个参数的话,使用 & 符号进行分隔。

    08-Ajax_第33张图片

    使用原生ajax发起POST请求

    步骤

    • 创建 xhr 对象

    • 调用 xhr.open() 函数 , 设置请求方式请求地址

    • 设置请求头设置 Content-Type 属性

    • 调用 xhr.send() 函数,同时指定要发送的数据

    • 监听 xhr.onreadystatechange 事件

    post请求参数的格式

    • 位置:send()方法的参数
    • 格式: 键值对字符串 xhr.send(‘bookname=老李的两天&author=laoli&publisher=heima’)
            // 第1步,创建ajax对象
            var xhr = new XMLHttpRequest()
            // 第2步,设置请求方式和请求地址
            xhr.open('post', 'http://www.liulongbin.top:3006/api/addbook')
            // 第3步,设置请求头
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
            // 第4步,发送请求
            xhr.send('bookname=老李的两天&author=laoli&publisher=heima')
            // 第5步,监听onreadystatechange事件
            xhr.onreadystatechange = function() {
                // 判断请求是否成功
                if (xhr.readyState === 4 && xhr.status === 200) {
                    console.log(xhr.responseText)
                }
            }
    

    数据交换格式

    什么是数据交换格式

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

    前端领域,经常提及的两种数据交换格式分别是 XMLJSON

    08-Ajax_第34张图片

    XML和HTML的区别

    • HTML 被设计用来描述网页上的内容,是网页内容的载体

    • XML 被设计用来传输和存储数据,是数据的载体

    JSON

    什么是JSON

    概念:JSON 的英文全称是 JavaScript Object Notation,即“JavaScript 对象的字符串表示法”。简单来讲,

    JSON 的本质是字符串

    作用:JSON 是一种轻量级的文本数据交换格式,在作用上类似于 XML,专门用于存储和传输数据,但

    JSONXML 更小、更快、更易解析。

    JSON的两种结构

    JSON 就是用字符串来表示 Javascript 的对象和数组。所以,JSON 中包含对象数组两种结构,通过这

    对象结构

    对象结构在 JSON 中表示为 { } 括起来的内容。数据结构为 { key: value, key: value, … } 的键

    值对结构。其中,key 必须是使用英文的双引号包裹的字符串,value 的数据类型可以是数字、字符串、

    布尔值、null、数组、对象6种类型。

    08-Ajax_第35张图片
    数组结构

    数组结构在 JSON 中表示为 [ ] 括起来的内容。数据结构为 [ "java", "javascript", 30, true … ]

    数组中数据的类型可以是数字、字符串、布尔值、null、数组、对象6种类型。

    JSON语法注意事项

    ① 属性名必须使用双引号包裹

    ② 字符串类型的值必须使用双引号包裹

    JSON 中不允许使用单引号表示字符串

    JSON 中不能写注释

    JSON 的最外层必须是对象或数组格式

    ⑥ 不能使用 undefined 或函数作为 JSON 的值

    **JSON 的作用:**在计算机与网络之间存储和传输数据。

    JSON 的本质:字符串来表示 Javascript 对象数据或数组数据

    JSON和JS对象的关系

    JSONJS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。例如:

    08-Ajax_第36张图片

    JSON和JS对象的互转

    要实现从 JSON 字符串转换为 JS 对象,使用 JSON.parse() 方法:

    image-20220218225639858

    要实现从 JS 对象转换为 JSON 字符串,使用 JSON.stringify() 方法:

    image-20220218225612443

    对象转成json字符串—序列化操作----例子;把数组保存到本地存储!

    var obj = { name: 'lisi', age: 20, hobby: ['吃饭', '睡觉', '打豆豆'] }
    var str = JSON.stringify(obj)
    console.log(str) // {"name":"lisi","age":20,"hobby":["吃饭","睡觉","打豆豆"]}
    console.log(typeof str) // string
    

    json字符串转回对象—反序列化操作----例子:使用原生ajax获取到的图书数据就是json字符串。

    var s = '{"name":"lisi","age":20,"hobby":["吃饭","睡觉","打豆豆"]}'
    var o = JSON.parse(s)
    console.log(o) // 可以展开的对象
    
    Object
    age: 20
    hobby: (3) ['吃饭', '睡觉', '打豆豆']
    name: "lisi"
    [[Prototype]]: Object
    

    JSON.parse() 应用

        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4 && xhr.status === 200) {
            console.log(xhr.responseText)
            console.log(typeof xhr.responseText)
            // JSON 字符串转 JOSN 对象 ===> 对象可以展开
            var result = JSON.parse(xhr.responseText)
            console.log(result)
          }
        }
    

    封装自己的Ajax函数

    配置对象中可以配置如下属性:

    • method 请求的类型
    • url 请求的 URL 地址
    • data 请求携带的数据
    • success 请求成功之后的回调函数

    处理data参数

    需要把 JSON 对象转 JSON 字符串 , data 里面接收的是字符串 , 程序员输入的是对象

    /*** 处理 data 参数
    * @param {data} 需要发送到服务器的数据
    * @returns {string} 返回拼接好的查询字符串 name=zs&age=10
    */
    function resolveData(data) {
      var arr = []
      for (var k in data) {
        var str = k + '=' + data[k]
        arr.push(str)
      }
    
      return arr.join('&')
    }
    

    定义 npAjax 函数

    function npAjax(options) {
      var xhr = new XMLHttpRequest()
    
      // 把外界传递过来的参数对象,转换为 查询字符串
      // 处理参数数据--从对象 =====> 键值对字符串(get和post请求参数的格式都是键值对)
      var qs = resolveData(options.data)
      // 注册监听
      xhr.onreadystatechange = function () {
      // 注册监听
        if (xhr.readyState === 4 && xhr.status === 200) {
          // 把服务器的json字符串转成js对象
          var result = JSON.parse(xhr.responseText)
          options.success(result)
        }
      }
    }
    

    判断请求的类型

    不同的请求类型,对应 xhr 对象的不同操作,因此需要对请求类型进行 if … else … 的判断:

    if (options.method.toUpperCase() === 'GET') {
      // 发起GET请求
      xhr.open(options.method, options.url + '?' + qs)
      xhr.send()
    } else if (options.method.toUpperCase() === 'POST') {
      // 发起POST请求
      xhr.open(options.method, options.url)
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
      xhr.send(qs)
    }
    
    • 封装一个函数—发送ajax请求的
    // 封装一个函数---发送ajax请求的
    function npAjax (options) {
      // 配置对象 {method:'',url:'',data:{},success: function(){}}
      // console.log(options)
      // 创建ajax对象
      var xhr = new XMLHttpRequest()
    
      // 处理参数数据--从对象 =====> 键值对字符串(get和post请求参数的格式都是键值对)
      var qs = resolveData(options.data)
      // console.log(qs)
    
      // 判断请求方式
      if (options.method.toUpperCase() === 'GET') {
        // console.log('发送get请求')
        xhr.open('GET', options.url + '?' + qs)
        xhr.send()
    
      } else if (options.method.toUpperCase() === 'POST') {
        // console.log('发送post请求')
        xhr.open('POST', options.url)
        // 设置请求头
        xhr.setRequestHeader('Content-Type', 'application/x-www-url-encoded')
        xhr.send(qs)
      }
      // 监听onreadystatechange事件了
      xhr.onreadystatechange = function () {
        // 判断请求是否成功
        if (xhr.readyState === 4 && xhr.status === 200) {
          // console.log('请求成功了')
          // console.log('服务器响应的数据是', xhr.responseText)
          // 把服务器响应的json字符串,转回对象
          var data = JSON.parse(xhr.responseText)
          // console.log(data)
          // 执行成功之后的回调函数
          options.success(data)
        }
      }
    
    }
    
    function resolveData (obj) {
      // { bookname: '三国演义', author: '罗贯中' }
      // 'bookname=三国演义&author=罗贯中'
      var str = ''
      // 遍历对象 for in
      for (var k in obj) {
        str += '&' + k + '=' + obj[k]
      }
      str = str.substring(1) // 从索引为1开始截 , 返回新的字符串
      return str
    }
    

    如何对URL进行编码与解码

    浏览器提供了 URL 编码与解码的 API,分别是:

    • encodeURI() 编码的函数
    • decodeURI() 解码的函数

    08-Ajax_第37张图片

    XMLHttpRequest Level2的新特性

    • 可以设置 HTTP 请求的时限

    • 可以使用 FormData 对象管理表单数据

    • 可以上传文件

    • 可以获得数据传输的进度信息

    1. 设置HTTP请求时限

    <script>
      // 创建ajax对象
      var xhr = new XMLHttpRequest()
      // 设置请求方式和请求地址
      xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks')
      // 设置 超时时间
      xhr.timeout = 30
      // 设置超时以后的处理函数
      xhr.ontimeout = function () {
        console.log('请求超时了!')
      }
      // 发送请求
      xhr.send()
      // 监听onreadystatechange事件
      xhr.onreadystatechange = function () {
        // 判断请求是否成功
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.responseText)
        }
      }
    </script> 
    

    FormData对象管理表单数据

    • 无表单的情况(对象模拟数据)
     // 1. 新建 FormData 对象
     var fd = new FormData()
     // 2. 为 FormData 添加表单项 // .append(键, 值)
     fd.append('uname', 'zs')
     fd.append('upwd', '123456')
     // 3. 创建 XHR 对象 
     var xhr = new XMLHttpRequest()
     // 4. 指定请求类型与URL地址
     xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
     // 把formdata对象放入send()方法中
     // 数据是formdata格式,不要设置请求头
     xhr.send(fd)
     // 监听onreadystatechange事件
      xhr.onreadystatechange = function () {
        // 判断请求是否成功
        if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.responseText)
        }
      }
    
    • 有表单的情况
    // 获取表单元素
    var form = document.querySelector('#form1')
    // 监听表单元素的 submit 事件
    form.addEventListener('submit', function(e) {
         // 阻止默认提交行为
         e.preventDefault()
         // 收集数据---formdata对象来收集
         // var fd = new FormData(表单对象)
         // 根据 form 表单创建 FormData 对象,会自动将表单数据填充到 FormData 对象中
         var fd = new FormData(form)
         // 创建ajax对象
         var xhr = new XMLHttpRequest()
         // 设置请求方式和请求地址
         xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
         // 把formdata对象放入send()方法中
         // 数据是formdata格式,不要设置请求头
         xhr.send(fd)
         // 监听onreadystatechange事件
         xhr.onreadystatechange = function() {
         // 判断请求是否成功
         if (xhr.readyState === 4 && xhr.status === 200) {
          console.log(xhr.responseText)         
         }
    })
    

    2. 使用formdata对象和$.ajax()向服务器提交数据

    如果数据是formdata对象,那么在使用$.ajax()提交数据时,需要额外的配置

          // 使用formdata对象模拟数据
          var fd = new FormData();
          fd.append("uname", "laoli");
          fd.append("upwd", "aoe1234");
          $.ajax({
            method: "post",
            url: "http://www.liulongbin.top:3006/api/formdata",
            // data: {}
            data: fd,
            // 不需要设置请求头!
            contentType: false,
            // 默认会把data中的数据转成键值对字符串,但是此时不需要转
            processData: false,
            success: function (res) {
              console.log(res);
            },
          });
    

    3. 上传文件

    新版 XMLHttpRequest 对象,不仅可以发送文本信息,还可以上传文件。

    实现步骤:

    ① 定义 UI 结构

    ② 验证是否选择了文件

    ③ 向 FormData 中追加文件

    ④ 使用 xhr 发起上传文件的请求

    ⑤ 监听 onreadystatechange 事件

    1. 定义UI结构
     
     <input type="file" id="file1" />
     
     <button id="btnUpload">上传文件button>
     <br />
     
     <img src="" alt="" id="img" width="800" />
    
    2. 验证是否选择了文件

    https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/input/file

    // 1. 获取上传文件的按钮
    var btnUpload = document.querySelector('#btnUpload')
    // 2. 为按钮添加 click 事件监听
    btnUpload.addEventListener('click', function() {
     	// 3. 获取到选择的文件列表
         var files = document.querySelector('#file1').files
         if (files.length <= 0) {
         return alert('请选择要上传的文件!')
         }
         // ...后续业务逻辑
    })
    
    3. 向FormData中追加文件
    // 1. 创建 FormData 对象
    var fd = new FormData()
    // 2. 向 FormData 中追加文件
    fd.append('avatar', files[0])
    
    4. 使用 xhr 发起上传文件的请求
    // 1. 创建 xhr 对象
    var xhr = new XMLHttpRequest()
    // 2. 调用 open 函数,指定请求类型与URL地址。其中,请求类型必须为 POST
    xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar')
    // 3. 发起请求
    xhr.send(fd)
    
    5. 监听onreadystatechange事件
    xhr.onreadystatechange = function() {
     if (xhr.readyState === 4 && xhr.status === 200) {
     	 var data = JSON.parse(xhr.responseText)
         if (data.status === 200) { // 上传文件成功
         // 将服务器返回的图片地址,设置									为  标签的 src 属性
            document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url
         } else { // 上传文件失败
             console.log(data.message)
         }
     }
    }
    
            /* 
                    需求:单击按钮,上传文件给服务器
                    分析:
                        1)给按钮绑定点击事件
                        2)获取用户选择的文件
                        3)发送ajax请求,上传文件
                */
            var uploadBtn = document.querySelector('#uploadBtn')
            uploadBtn.addEventListener('click', function() {
                // 获取到文件选择框
                var file1 = document.querySelector('#file1')
                // console.log(file1.files)
                // 判断用户是否选择了文件
                if (file1.files.length <= 0) {
                    return alert('请选择文件!')
                }
    
                // 获取用户选中的文件            
                file = file1.files[0]
                // console.log(file)
                // 使用FormData收集数据
                var fd = new FormData()
                fd.append('avatar', file)
    
                // 发送ajax请求
                var xhr = new XMLHttpRequest()
                xhr.open('post', 'http://www.liulongbin.top:3006/api/upload/avatar')
                xhr.send(fd)
                xhr.onreadystatechange = function() {
                    // 判断请求是否成功
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        console.log('请求成功了', xhr.responseText)
                        // 把服务器响应的json字符串转成对象
                        var data = JSON.parse(xhr.responseText)
                        console.log(data)
                        // data.url 图片在服务器的保存路径 /uploads/1645407308427_3d76ba7c13ad4ce295214ff040858c6b.jpg
                        // 给img标签设置src属性,展示图片
                        document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url
                    }
                }
            })
    
    6. 显示文件上传进度
    计算文件上传进度

    新版本的 XMLHttpRequest 对象中,可以通过监听 xhr.upload.onprogress 事件,来获取到文件的上传进度。语法格式如下:

    e.lengthComputable 文件是否可计算大小

    已上传的大小 / 总文件大小

    // 创建 XHR 对象
    var xhr = new XMLHttpRequest()
    // 监听 xhr.upload 的 onprogress 事件
    xhr.upload.onprogress = function(e) {
         // e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
         if (e.lengthComputable) {
             // e.loaded 已传输的字节
             // e.total 需传输的总字节
             var percentComplete = Math.ceil((e.loaded / e.total) * 100) + "%"
         }
     }
    
    导入需要的库
    <link rel="stylesheet" href="./lib/bootstrap.css" />
    <script src="./lib/jquery.js">script>
    
    基于Bootstrap渲染进度条
     
     <div class="progress" style="width: 500px; margin: 10px 0;">
         <div class="progress-bar progress-bar-info progress-barstriped active" id="percent" style="width: 0%">
         0%
         div>
     div>
    
    动态设置到进度条上
    xhr.upload.onprogress = function(e) {
         if (e.lengthComputable) {
             // 1. 计算出当前上传进度的百分比
             var percentComplete = Math.ceil((e.loaded / e.total) * 100)
             $('#percent')
             // 2. 设置进度条的宽度
             .attr('style', 'width:' + percentComplete + '%')
             // 3. 显示当前的上传进度百分比
             .html(percentComplete + '%')
             // $("#percent").css("width", percentComplete);
             // $("#percent").html(percentComplete);
         }
    }
    
    7. 监听上传完成的事件
    xhr.upload.onload = function() {
         $('#percent')
         // 移除上传中的类样式
         .removeClass()
         // 添加上传完成的类样式
         .addClass('progress-bar progress-bar-success')
    }
    

    jQuery高级用法- jQuery实现文件上传

    1. 定义UI结构

     
     <script src="./lib/jquery.js">script>
     
     <input type="file" id="file1" />
     
     <button id="btnUpload">上传button>
    

    2. 验证是否选择了文件

    $('#btnUpload').on('click', function() {
         // 1. 将 jQuery 对象转化为 DOM 对象,并获取选中的文件列表
         var files = $('#file1')[0].files
         // 2. 判断是否选择了文件
         if (files.length <= 0) {
         	return alert('请选择图片后再上传!‘)
         }
    })
    

    3. 向FormData中追加文件

    // 向 FormData 中追加文件
    var fd = new FormData()
    fd.append('avatar', files[0])
    // fd.append('avatar',files)
    

    4. 使用jQuery发起上传文件的请求

    $.ajax({
         method: 'POST',
         url: 'http://www.liulongbin.top:3006/api/upload/avatar',
         data: fd,
         // 不修改 Content-Type 属性,使用 FormData 默认的 Content-Type 值
         contentType: false,
         // 不对 FormData 中的数据进行 url 编码,而是将 FormData 数据原样发送到服务器
         processData: false,
         success: function(res) {
         	console.log(res)
              if (res.status === 200) {
                  $("img").attr("src", "http://www.liulongbin.top:3006" + res.url);
                }
         }
    })
    

    image-20201202232141504

    image-20201202232532680

    5. jQuery实现loading效果

    ajaxStart(callback)

    Ajax 请求开始时,执行 ajaxStart 函数。可以在 ajaxStartcallback 中显示 loading 效果,示例代码如下:

    // 自 jQuery 版本 1.8 起,该方法只能被附加到文档
    $(document).ajaxStart(function() {
        $('#loading').show()
    })
    

    注意: $(document).ajaxStart() 函数会监听当前文档内所有的 Ajax 请求

    ajaxStop(callback)

    Ajax 请求结束时,执行 ajaxStop 函数。可以在 ajaxStopcallback 中隐藏 loading 效果,示例代码如下:

    // 自 jQuery 版本 1.8 起,该方法只能被附加到文档
    $(document).ajaxStop(function() {
        $('#loading').hide()
    })
    

    axios

    什么是axios

    Axios 是专注于网络数据请求的库。

    相比于原生的 XMLHttpRequest 对象,axios 简单易用

    相比于 jQueryaxios 更加轻量化,只专注于网络数据请求。

    axios发起GET请求

    axios 发起 get 请求的语法:

    axios.get('url', { params: { /*参数*/ } }).then(callback)
    

    具体的请求示例如下:

    • res 是axios 封装的一个对象
    • res.data 才是服务器响应回来的数据
    // 请求的 URL 地址
    var url = 'http://www.liulongbin.top:3006/api/get'
    // 请求的参数对象
    var paramsObj = { name: 'zs', age: 20 }
    // 调用 axios.get() 发起 GET 请求
    axios.get(url, { params: paramsObj }).then(function(res) {
         // res.data 是服务器返回的数据
         var result = res.data
         console.log(res)
    })
    
            // 发送get请求
            $('#btn1').on('click', function() {
                /* 
                    axios.get('url地址', {params: 参数数据})
                */
                axios.get('http://www.liulongbin.top:3006/api/getbooks', { params: { bookname: '三国演义' } }).then(function(res) {
                    // 请求成功之后的回调函数
                    // res 是axios封装的一个对象
                    // res.data 才是服务器响应回来的数据
                    console.log(res)
                    console.log(res.data)
                })
            })
    

    axios发起POST请求

    axios 发起 post 请求的语法:

    axios.post('url', { /*参数*/ }).then(callback)
    

    具体的请求示例如下:

    // 请求的 URL 地址
    var url = 'http://www.liulongbin.top:3006/api/post'
    // 要提交到服务器的数据
    var dataObj = { location: '北京', address: '顺义' }
    // 调用 axios.post() 发起 POST 请求
    axios.post(url, dataObj).then(function(res) {
         // res.data 是服务器返回的数据
         var result = res.data
         console.log(result)
    })
    
            // 发送post请求
            $('#btn2').on('click', function() {
                // axios.post('url', { /*参数*/ }).then(callback)
                axios.post('http://www.liulongbin.top:3006/api/addbook', { bookname: '老李的一天', author: 'laoli', publisher: '黑马' }).then(function(res) {
                    console.log(res)
                    console.log(res.data)
                })
            })
    

    直接使用axios发起请求

    axios 也提供了类似于 jQuery$.ajax() 的函数,语法如下:

    axios({
     method: '请求类型',
     url: '请求的URL地址',
     data: { /* POST数据 */ },
     params: { /* GET参数 */ }
    }).then(callback)
    

    发起get请求

    document.querySelector('#btn3').addEventListener('click', function () {
          var url = 'http://www.liulongbin.top:3006/api/get'
          var paramsData = { name: '钢铁侠', age: 35 }
          axios({
            method: 'GET',
            url: url,
            params: paramsData
          }).then(function (res) {
            console.log(res.data)
          })
    })
    

    发起post请求

    document.querySelector('#btn4').addEventListener('click', function () {
      axios({
        method: 'POST',
        url: 'http://www.liulongbin.top:3006/api/post',
        data: {
          name: '娃哈哈',
          age: 18,
          gender: '女'
        }
      }).then(function (res) {
        console.log(res.data)
      })
    })
    
            $('#btn3').on('click', function() {
                // 发送get请求
                axios({
                    method: 'get',
                    url: 'http://www.liulongbin.top:3006/api/getbooks',
                    params: { bookname: '三国演义' }
                }).then(function(res) {
                    console.log(res)
                    console.log(res.data)
                })
            })
            // ---------------------------------------------------------------
            $('#btn4').on('click', function() {
                // 发送post请求
                axios({
                    method: 'post',
                    url: 'http://www.liulongbin.top:3006/api/addbook',
                    data: { bookname: '老李的两天', author: '老李', publisher: 'heima' }
                }).then(function(res) {
                    console.log(res)=
                    console.log(res.data)
                })
            })
    

    同源策略

    什么是同源

    如果两个页面的协议域名端口都相同,则两个页面具有相同的源

    什么是同源策略

    同源策略(英文全称 Same origin policy)是浏览器的一种安全机制 , 禁止向非同源的 url 发送 ajax请求. (请求能发出去 , 但是会报错)

    MDN 官方给定的概念:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这

    是一个用于隔离潜在恶意文件的重要安全机制

    通俗的理解:浏览器规定,A 网站的 JavaScript,不允许和非同源的网站 C 之间,进行资源的交互,例如:

    ① 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB

    ② 无法接触非同源网页的 DOM

    ③ 无法向非同源地址发送 Ajax 请求

    跨域

    什么是跨域

    跨域请求 : 向非同源的 url 发送跨域请求

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

    网页:http://www.test.com/index.html

    接口:http://www.api.com/userlist

    浏览器对跨域请求的拦截

    08-Ajax_第38张图片

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

    如何实现跨域数据请求

    现如今,实现跨域数据请求,最主要的两种解决方案,分别是 JSONPCORS

    **JSONP:**出现的早,兼容性好(兼容低版本IE)。是前端程序员为了解决跨域问题,被迫想出来的一种临时解决方案。缺点是只支持 GET 请求,不支持 POST 请求。

    **CORS:**出现的较晚,它是 W3C 标准,属于跨域 Ajax 请求的根本解决方案。支持 GETPOST 请求。缺点是不兼容某些低版本的浏览器

    JSONP的实现原理

    由于浏览器同源策略的限制,网页中无法通过 Ajax 请求非同源的接口数据。但是

    你可能感兴趣的:(ajax,javascript)