0
点赞
收藏
分享

微信扫一扫

08-Ajax

Java旺 2022-03-12 阅读 25

服务器相关概念

1. 客户端与服务器

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

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

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

1.URL的概念

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

2. URL的组成

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

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

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

端口号

端口号 80 可以省略不写

image-20220214094800102

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能让我们轻松实现 网页服务器之间的 数据交互

image-20220214102219662

Ajax应该用场景

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

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

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

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

jQuery中的Ajax

image-20220214103107360

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

image-20220214103043178

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

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

url 地址错误

image-20220214104830201

$.get() 函数介绍

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

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

$.get(url,[data],[callback]) []:可选参数
image-20220214103622944
  • $.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);
        });
      });
image-20220214110801958

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() 注意事件

image-20220217092636089
  • 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方式请求接口的过程
image-20220214141502215
POST方式请求接口的过程
image-20220214141514001

3. 接口文档

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

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

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

4. 接口测试工具

1. 什么是接口测试工具

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

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

常用的就是:PostMan

2. 了解 Postman 界面结构
image-20220214143730971
3. 使用PostMan测试GET接口

image-20220214143749786

4. 使用PostMan测试POST接口
image-20220214143820450
5. 错误提示

url 地址错误

image-20220214104830201

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

image-20220214145600434

两个案例

图书管理

UI界面搭建

需要使用到的库和插件

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

image-20200801203656243

搭建步骤

  • 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> 元素添加 .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 = `
     <tr>
        <td>${item.id}</td>
        <td>${item.bookname}</td>
        <td>${item.author}</td>
        <td>${item.publisher}</td>
        <td><a href="javascript:;" class="del" data-id=${item.id}>删除</a></td>
      </tr>`;
                //   把遍历出来的数据 追加到空数组里
                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 = `
      <li class="right_word">
            <img src="img/person02.png" /> <span>${text}</span>
          </li>`;
    $("#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 = `
              <li class="left_word">
                  <img src="img/person01.png" /> <span>${res.data.info.text}</span>
              </li>`;
          $("#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 属性,而且指定了 autoplay,那么,语音就会自动播放 -->
  <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来重置表单
image-20220217093637787

<form> 标签的属性(⭐⭐⭐)

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

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

target
  • target 属性用来规定 在何处打开 action URL
  • _blank 在新窗口打开
  • _self 在相同窗口打开
  • 默认情况下,target的值是 _self,表示在相同的框架中打开 action URL
image-20220217095200712
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 的行为,叫做表单的同步提交

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

解决方案

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

通过Ajax提交表单数据

1. 监听表单提交事件

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

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

image-20220217103344421
      $("#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. 如何快速获取表单数据(⭐⭐⭐)

image-20220217104705087

serialize() 函数

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

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

$("#form").serialize();
image-20220217110221405

具体实现步骤

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 = `
       <li class="list-group-item">
          <span class="badge" style="background-color: #F0AD4E;">评论时间:${item.username}</span>
          <span class="badge" style="background-color: #5BC0DE;">评论人:${item.time}</span>
         ${item.content}
       </li>`;
          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页面

image-20220217143644204

模板引擎的好处

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

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
  • 找到 安装 导航栏,找到下载链接,右键下载即可
image-20220217144221410

基本使用(⭐⭐⭐)

image-20220217144653918

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>我是h1标签</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

示例代码如下:

分组

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

字符串的 replace 函数

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

image-20220219144721754
多次replace
image-20220219145205499
使用循环来replace
image-20220219145534345

替换真实的内容

image-20220219145814972

实现简易的模板引擎

  • 定义模板结构

  • 预调用模板引擎

  • 封装 template 函数

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


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);
        }
      };

请求转态和响应转态

image-20220218234135303

xhr对象的readyState属性

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

image-20220218202319512

使用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 的末尾,然后再加上 参数=值 ,想加上多个参数的话,使用 & 符号进行分隔。

image-20220218203621059

使用原生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

image-20220218224646661

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种类型。

image-20220218225208457
数组结构

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

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

JSON语法注意事项

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

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

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

JSON 中不能写注释

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

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

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

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

JSON和JS对象的关系

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

image-20220218225438552

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() 解码的函数

image-20220306173621717

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结构
 <!-- 1. 文件选择框 -->
 <input type="file" id="file1" />
 <!-- 2. 上传按钮 -->
 <button id="btnUpload">上传文件</button>
 <br />
 <!-- 3. 显示上传到服务器上的图片 -->
 <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) { // 上传文件成功
     // 将服务器返回的图片地址,设置									为 <img> 标签的 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结构

 <!-- 导入 jQuery -->
 <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

浏览器对跨域请求的拦截

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

如何实现跨域数据请求

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

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

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

JSONP的实现原理📝

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

源策略的影响,可以通过 src 属性,请求非同源的 js 脚本。

JSONP实现原理 : 动态创建一个

JSONP 缺点

由于 JSONP 是通过 <script> 标签的 src 属性,来实现跨域数据获取的,所以,JSONP 只支持 GET 数据请求,不支持 POST 请求。

image-20220221155511235

实现步骤 :

    <script>
      function name(params) {
        console.log("name");
        console.log(params);
      }
    </script>
    <script src="http://www.liulongbin.top:3006/api/jsonp?callback=name"></script>

单击按钮发送 jsonp 请求

    <script>
      function slf(data) {
        console.log("slf");
        console.log(data);
      }
    </script>

      // 单击按钮发送 jsonp 请求
      let btn = document.querySelector("#btn");
      btn.addEventListener("click", function () {
        // 1.创建script 标签
        let script = document.createElement("script");
        // 2.设置 src 属性
        script.src = "http://www.liulongbin.top:3006/api/jsonp?callback=slf";
        // 3.script 加载如页面
        document.body.appendChild(script);
        // onload 页面加载完事件
        // 标签请求结束 删除script 标签
        script.onload = function () {
          document.body.removeChild(this);
        };
      });

使用 ajax 发送jsonp请求

      $("#btn").on("click", function () {
        $.ajax({
          method: "get",
          url: "http://www.liulongbin.top:3006/api/jsonp",
          // 设置要发送的 jsonp请求
          dataType: "jsonp",
          // 自定义参数名称
          //   jsonp:"abc",
          // 自定义函数名字
          //   jsonopCabblack:"二恶狗",
          success: function (res) {
            console.log(res);
          },
        });
      });

jQueryJSONP的实现过程

jQuery 中的 JSONP,也是通过 <script> 标签的 src 属性实现跨域数据访问的,只不过,jQuery 采用的是动态创建和移除标签的方式,来发起 JSONP 数据请求。

  • 在发起 JSONP 请求的时候,动态向 <header> 中 append 一个 <script> 标签;

  • JSONP 请求成功以后,动态从 <header> 中移除刚才 append 进去的 <script> 标签;

防抖📝

什么是防抖

防抖策略 当事件被触发是不会立即执行 , 延迟 n 秒后再执行回调 , 如果在这 n 秒内事件又被触发 , 则重新计算.

好处 :当频繁的触发某件事情时 , 我们能保证这个事件最终只能执行一次 , 能够减少一些不必要的回调执行 . 减少请求次数,节约请求资源;

防抖的应用场景

用户在输入框中连续输入一串字符时,可以通过防抖策略,只在输入完后,才执行查询的请求,这样可以有效减少请求次数,节约请求资源;

实现输入框的防抖

  • 防抖动的 timer
  • 定义防抖的函数,函数里面定义一个延时器,在延时器里面调用发起JSONP的请求
  • 在触发 keyup 事件时,立即清空 timer,然后调用防抖的函数
var timer = null // 1. 防抖动的 timer
function debounceSearch(keywords) { // 2. 定义防抖的函数
     timer = setTimeout(function() {
         // 发起 JSONP 请求
         getSuggestList(keywords)
     }, 500)
 }
$('#ipt').on('keyup', function() { // 3. 在触发 keyup 事件时,立即清空 timer
     clearTimeout(timer)
     // ...省略其他代码
     debounceSearch(keywords)
 })
缓存搜索的建议列表
定义全局缓存对象
 // 缓存对象
 var cacheObj = {}
将搜索结果保存到缓存对象中
  • 键就是用户输入的关键字,值就是服务器返回的value
// 渲染建议列表
function renderSuggestList(res) {
     // ...省略其他代码
     // 将搜索的结果,添加到缓存对象中
     var k = $('#ipt').val().trim()
     cacheObj[k] = res
}
优先从缓存中获取搜索建议
  • 在发起请求之前,先判断缓存中是否有数据
// 监听文本框的 keyup 事件
$('#ipt').on('keyup', function() {
     // ...省略其他代码
     // 优先从缓存中获取搜索建议
     if (cacheObj[keywords]) {
     	return renderSuggestList(cacheObj[keywords])
     }
     // 获取搜索建议列表
     debounceSearch(keywords)
 })

节流📝

什么是节流

节流策略throttle),可以减少一段时间内事件的触发频率。防止事件无限制触发 . 间隔时间内再去触发不会有任何效果

节流的应用场景

① 鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;

② 懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费 CPU 资源;

节流案例 鼠标跟随效果

不使用节流时实现鼠标跟随效果

$(function() {
     // 获取图片元素
     var angel = $('#angel')
     // 监听文档的 mousemove 事件
     $(document).on('mousemove', function(e) {
     // 设置图片的位置
     	$(angel).css('left', e.pageX + 'px').css('top', e.pageY + 'px')
     })
})

节流阀的概念

  • 节流阀为空,表示可以执行下次操作;不为空,表示不能执行下次操作。

  • 当前操作执行完,必须将节流阀重置为空,表示可以执行下次操作了。

  • 每次执行操作前,必须先判断节流阀是否为空

使用节流优化鼠标跟随效果

  • 预定义一个 timer 节流阀
  • 当设置了鼠标跟随效果后,清空 timer 节流阀,方便下次开启延时器
  • 执行事件的时候判断节流阀是否为空,如果不为空,则证明距离上次执行间隔不足16毫秒
$(function() {
     var angel = $('#angel')
     var timer = null // 1.预定义一个 timer 节流阀
     $(document).on('mousemove', function(e) {
         if (timer) { return } // 3.判断节流阀是否为空,如果不为空,则证明距离上次执行间隔不足16毫秒
         timer = setTimeout(function() {
             $(angel).css('left', e.pageX + 'px').css('top', e.pageY + 'px')
             timer = null // 2.当设置了鼠标跟随效果后,清空 timer 节流阀,方便下次开启延时器
         }, 16)
     })
})

总结防抖和节流的区别

  • 防抖:如果事件被频繁触发,防抖能保证只有最后一次触发生效!前面 N 多次的触发都会被忽略!

  • 节流:如果事件被频繁触发,节流能够减少事件触发的频率,因此,节流是有选择性地执行一部分事件!

HTTP协议简介

image-20220219150958537

什么是通信协议

是指通信的双方完成通信所必须遵守规则和约定

通俗的理解:通信双方采用约定好的格式来发送和接收消息,这种事先约定好的通信格式,就叫做通信协议

互联网中的通信协议

客户端与服务器之间要实现网页内容的传输,则通信的双方必须遵守网页内容的传输协议。

网页内容又叫做超文本,因此网页内容的传输协议又叫做超文本传输协议(HyperText Transfer Protocol) ,简称 HTTP 协议

HTTP(⭐⭐⭐)

什么是HTTP协议

HTTP 协议即超文本传送协议 (HyperText Transfer Protocol) ,它规定了客户端与服务器之间进行网页内容传输时,所必须遵守的传输格式。

例如:

  • 客户端要以HTTP协议要求的格式把数据提交到服务器
  • 服务器要以HTTP协议要求的格式把内容响应给客户端
HTTP协议的交互模型

HTTP 协议采用了 请求/响应 的交互模型。

image-20220219151610872

HTTP请求消息

由于 HTTP 协议属于客户端浏览器和服务器之间的通信协议。因此,客户端发起的请求叫做 HTTP 请求客户端发送到服务器的消息,叫做 HTTP 请求消息

注意:HTTP 请求消息又叫做 HTTP 请求报文

什么是请求报文和响应报文

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

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

HTTP请求消息的组成部分

HTTP 请求消息由请求行request line)、请求头部header ) 、空行请求体 4 个部分组成。

image-20220219152646468

注意 :

  • 在浏览器中,GET 请求比较特殊,它只有请求头没有请求体

  • 在浏览器中,POST、PUT、PATCH、DELETE 请求既有请求头,又有请求体。

1. 请求行

请求行请求方式URLHTTP 协议版本 3 个部分组成,他们之间使用空格隔开。

image-20220219153556523

2. 请求头部

请求头部用来描述客户端的基本信息,从而把客户端相关的信息告知服务器。比如:User-Agent 用来说明当前是什么类型的浏览器;

比如:User-Agent 用来说明当前是什么类型的浏览器;Content-Type 用来描述发送到服务器的数据格式;Accept 用来描述客户端能够接收什么类型的返回内容;Accept-Language 用来描述客户端期望接收哪种人类语言的文本内容。

请求头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔

image-20220219153946500

请求头部 – 常见的请求头字段

image-20220219154000686 image-20220219154215717

关于更多请求头字段的描述,可以查看 MDN 官方文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

3. 空行

最后一个请求头字段的后面是一个空行,通知服务器请求头部至此结束

请求消息中的空行,用来分隔请求头部与请求体

image-20220219154344116

4. 请求体

请求体中存放的,是要通过 POST 方式提交到服务器的数据。

注意:只有 POST 请求才有请求体GET 请求没有请求体

HTTP响应消息

响应消息就是服务器响应给客户端的消息内容,也叫作响应报文

HTTP响应消息的组成部分

HTTP响应消息由状态行响应头部空行响应体 4 个部分组成

image-20220219154751139

1. 状态行

状态行HTTP 协议版本状态码状态码的描述文本 3 个部分组成,他们之间使用空格隔开

image-20220219155103223

2. 响应头部

响应头部用来描述服务器的基本信息。响应头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔。

image-20220219155328305

响应头部 – 常见的响应头字段

image-20220219155551004

关于更多响应头字段的描述,可以查看 MDN 官方文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

3. 空行

在最后一个响应头部字段结束之后,会紧跟一个空行,用来通知客户端响应头部至此结束

响应消息中的空行,用来分隔响应头部响应体

image-20220219155702949

4. 响应体

响应体中存放的,是服务器响应给客户端的资源内容

image-20220219155846860

HTTP请求方法

什么是HTTP请求方法

HTTP 请求方法,属于 HTTP 协议中的一部分,请求方法的作用是:用来表明要对服务器上的资源执行的操作。最常用的请求方法是 GETPOST

HTTP的请求方法

image-20220219160125425

HTTP响应状态码

什么是HTTP响应状态码

概念:http 响应状态码(Status Code)由三个十进制数字组成第一个十进制数字定义了状态码的类型,用来标识响应成功与否的状态

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

HTTP 状态码共分为 5 种类型:

image-20220219161800089

常见的HTTP响应状态码(⭐⭐⭐)

2** 成功相关的响应状态码

2** 范围的状态码,表示服务器已成功接收到请求并进行处理。常见的 2** 类型的状态码如下:

3** 重定向相关的响应状态码

3** 范围的状态码,表示表示服务器要求客户端重定向,需要客户端进一步的操作以完成资源的请求。常见的 3** 类型的状态码如下:

4** 客户端错误相关的响应状态码

4** 范围的状态码,表示客户端的请求有非法内容,从而导致这次请求失败。常见的 4** 类型的状态码如下:

5** 服务端错误相关的响应状态码

5** 范围的状态码,表示服务器未能正常处理客户端的请求而出现意外错误。常见的 5** 类型的状态码如下

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

正确区分响应状态码业务状态码的不同 , 从如下 3 个方面进行区分:

  • 所处的位置
  • 表示的结果
  • 通用性

1. 所处的位置不同

  • 响应头状态行中所包含的状态码,叫做“响应状态码

  • 响应体数据中所包含的状态码,叫做“业务状态码

image-20220219164354101

2. 表示的结果不同

  • 响应状态码只能表示这次请求的成功与否(成功地失败了)
  • 业务状态码用来表示这次业务处理的成功与否
image-20220219164533054

3. 通用性不同

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

业务状态码后端程序员自定义的,不具有通用性

image-20220306173919039

举报

相关推荐

0 条评论