ajax学习

文章目录

服务器的基本概念

1、客户端与服务器

上网的本质目的:通过互联网的形式来获取和消费资源

(1)服务器

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

(2)客户端

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

个人电脑中,可以通过安装浏览器的形式,访问服务器对外提供的各种资源

2、URL地址

(1)概念

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

常见的URL举例:
http://www.baidu.com

(2)组成部分

URL地址一般由三部组成:

  • 客户端与服务器之间的通信协议
  • 存有该资源的服务器名称
  • 资源在服务器上具体的存放位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E1VJ0sT8-1669643354972)(1669295026751.png)]

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

(1)图解客户端与服务器的通信过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-90dy0RkU-1669643354974)(1669295228199.png)]

注意!

  • 客户端与服务器之间的通信过程,分为请求-处理-响应三个步骤。
  • 网页中的每一个资源,都是通过请求–处理–响应的方式从服务器获取回来的。

(2)基于浏览器的开发者工具分析通信过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ikqq0edC-1669643354977)(1669295401056.png)]

4、服务器对外提供了哪些资源

(1)列举网页中常见的资源

**常见资源:**文字内容,image图片,audio音频,video视频

数据是不是资源?

(2)数据也是资源

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

(3)数据是网页的灵魂

HTML是网页的骨架、CSS是网页的颜值、Javascript是网页的行为、数据,则是网页的灵魂

骨架、颜值、行为皆为数据服务

数据,在网页中无处不在

(4)网页中如何请求数据

数据,也是服务器对外提供的一种资源。只要是资源,必然要通过请求–处理–响应的方式进行获取。

如果要在网页中请求服务器上的数据资源,则需要用到XMLHttpRequest对象。

XMLHttpRequest (简称xhr)是浏览器提供的js成员,通过它,可以请求服务器上的数据资源。

最简单的用法 var xhrObj = new XMLHttpRequest()

(5)资源的请求方式

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

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

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

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

    例如:登录时向服务器提交的登录信息、注册时向服务器提交的注册信息、添加用户时向服

    务器提交的用户信息等各种数据提交操作

5、了解Ajax

(1)❔什么是ajax

Ajax的全称是Asynchronous Javascript And XML (异步JavaScript和XML).

**通俗的理解:**在网页中利用XMLHttpRequest对象和服务器进行数据交互的方式,就是Ajax,

(2)为什么要学ajax

之前所学的技术,只能把网页做的更美观漂亮,或添加一些动画效果,但是,Ajax能让我们轻松

实现网页与服务器之间的数据交互。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sv9UkYWw-1669643354979)(1669297639377.png)]

(3)ajax的典型应用场景

用户名检测:注册用户时,通过ajax的形式,动态检测用户名是否被占用

搜索提示:当输入搜索关键字时,通过ajax的形式,动态加载搜索提示列表

数据分页显示:当点击页码值的时候,通过ajax的形式,根据页码值动态刷新表格的数据

数据的增删改查:数据的增删改查操作,都需要通过ajax的形式,来实现数据的交互

6、jQuery中的Ajax

(1)了解jQuery中的Ajax

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

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

$.get() 获取数据

$.post() 提交数据

$.ajax() 获取提交数据

(2)$.get()获取数据

jQuery 中 $.get()函数的功能单一,专门用来发起get请求,从而将服务器上的资源请求到客户端来进行使用。

$.get(url,[data],[callback])
参数名参数类型是否必选说明
urlstring要请求的资源地址
dataobject请求资源期间要携带的参数
callbackfunction请求成功时的回到函数
1)$.get()发起不带参数的请求

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

<button id="btnGet">发起不带参数的get请求</button>
<script>
  $(function (){
    $('#btnGet').on('click',function (){
      //res代表服务器返回的数据
      $.get('http://www.liulongbin.top:3006/api/getbooks',function (res){
        console.log(res)
      })
    })
  })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OJMd3iIR-1669643354979)(1669346546016.png)]

2)$.get()发起带参数的请求
<button id="btnGetInfo">发起带参数的get请求</button>
<script>
  $(function (){
    $('#btnGetInfo').on('click',function (){
      //{id:1}参数
      $.get('http://www.liulongbin.top:3006/api/getbooks',{id:1},function (res){
        console.log(res)
      })
    })
  })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28busKL8-1669643354980)(1669347474032.png)]

(3)$.post()提交数据

jQuery 中 $.post()函数的功能单一,专门用来发起post请求,从而向服务器提交数据。

$.post(ur1,[data], [callback])
参数名参数类型是否必选说明
urlstring提交数据的地址
dataobject要提交的数据
callbackfunction数据提交成功时的回调函数
$.post()向服务器提交数据
<button id="btnPost">使用post提交数据</button>
<script>
  $(function (){
    $('#btnPost').on('click',function (){
      $.post('http://www.liulongbin.top:3006/api/addbook',{bookname:'水浒传',
        author:'施耐庵',publisher:'天津图书出版社'},function (res){
        console.log(res)
      })
    })
  })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TXWRXQ9V-1669643354981)(1669348274656.png)]

(4)$.ajax()获取提交数据

相比于 . g e t ( ) 和 .get()和 .get.post()函数,jQuery 中提供的$.ajax()函数,是一个功能比较综合的函数,它允许我们对Ajax请求进行更详细的配置。

$.ajax({
  type:'', //请求的方式,例如:GET、POST
  url:'',  //请求的url地址
  data:{},  //这次请求要携带的数据
  success:function (){}  //请求成功之后的回调函数
})
1)使用$.ajax()发起get请求

使用$.ajax()发起GET请求时,只需要将 type 属性的值设置为**‘GET’**即可

<button id="btnGet">使用$.ajax发起get请求</button>
<script>
  $(function (){
    $('#btnGet').on('click',function (){
      $.ajax({
        type:'GET', //请求的方式,例如:GET、POST,大小写都行,建议大写
        url:'http://www.liulongbin.top:3006/api/getbooks',  //请求的url地址
        data:{id:1},  //这次请求要携带的数据
        success:function (res){//请求成功之后的回调函数
          console.log(res)
        }
      })
    })
  })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x222IvqS-1669643354982)(1669349103848.png)]

2)使用$.ajax()发起post请求

使用$.ajax()发起POST请求时,只需要将 type 属性的值设置为**‘POST’**即可

<button id="btnPost">使用$.ajax发起post请求</button>
<script>
  $(function (){
    $('#btnPost').on('click',function (){
      $.ajax({
        type:'POST', //请求的方式,例如:GET、POST,大小写都行,建议大写
        url:'http://www.liulongbin.top:3006/api/addbook',  //请求的url地址
        data:{
            bookname:'水浒传',
            author:'施耐庵',
            publisher:'天津图书出版社'
        },  //这次请求要携带的数据
        success:function (res){//请求成功之后的回调函数
          console.log(res)
        }
      })
    })
  })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kkEDUAxX-1669643354982)(1669349369010.png)]

7、接口(请求地址)

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

请求方式

例如:

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

(1)通过GET方式请求接口的过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UR1oOzK5-1669643354983)(1669349740110.png)]

(2)通过POST方式请求接口的过程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gf1pFQDp-1669643354984)(1669349814631.png)]

(3)接口测试工具(PostMan、PostCode、apifox、apipost)

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

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

(4)接口文档

接口文档,顾名思义就是接口的说明文档,它是我们调用接口的依据。好的接口文档包含了对接口

URL,参数以及输出内容的说明,我们参照接口文档就能方便的知道接口的作用,以及接口如何进

行调用。

组成部分

接口文档可以包含很多信息,也可以按需进行精简,不过,一个合格的接口文档,应该包含以下6项

内容,从而为接口的调用提供依据:

1、接口名称:用来标识各个接口的简单说明,如登录接口,获取图书列表接口

2、**接口URL:**接口的调用地址。

3、调用方式:接口的调用方式,如GET或POST

4、参数格式:接口需要传递的参数,每个参数必须包含参数名称、参数类型、是否必选、参数说明

这4项内容。

5、响应格式:接口的返回值的详细描述,一般包含数据名称、数据类型、说明3项内容。

6、返回示例(可选):通过对象的形式,例举服务器返回数据的结构。

form表单与模板引擎

1、form表单的基本使用

(1)什么是表单

表单在网页中主要负责数据采集功能。HTML中的标签,就是用于采集用户输入的

信息,并通过标签的提交操作,把采集到的信息提交到服务器端进行处理。

(2)表单的组成部分

表单是由三个部分组成的:表单标签、表单域、表单按钮

表单域︰包含了文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框和文件上传框等。

(3)标签的属性

标签用来采集数据,标签的属性则是用来规定如何把采集到的数据发送到服务器。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcTE0Mtk-1669643354985)(1669383000989.png)]

1)action

action属性用来规定当提交表单时,向何处发送表单数据。

action属性的值应该是后端提供的一个URL地址,这个URL地址专门负责接收表单提交过来的数据。

当表单在未指定action属性值的情况下,action 的默认值为当前页面的URL地址。

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

<body>
  <form action="/login" target="_blank" method="post">
    <input type="text" name="email_or_mobile" />
    <input type="password" name="password" />
    <button type="submit">提交</button>
  </form>
</body>
2)target

target 属性用来规定在何处打开action URL

它的可选值有5个,默认情况下,target的值是_self,表示在相同的框架中打开action URL.

描述
_blank新窗口中打开
_self默认,在相同的框架中打开
_parent在父框架中打开
_top在整个窗口中打开
framename在指定的窗口中打开
3)method

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

它的可选值有两个,分别是get和 post。

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

get会把数据送到地址栏中,post更加隐蔽,更安全

注意:
get方式适合用来提交少量的、简单的数据。
post方式适合用来提交大量的、复杂的、或包含文件上传的数据。

在实际开发中,表单的post提交方式用的最多,很少用get。例如登录、注册、添加数据等表单操作,都需要使用post方式来提交表单。

4)enctype

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

它的可选值有三个,默认情况下enctype的值为 application/x-www-form-urlencoded,表示在发送前编码所有的字符。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8KXxB1m8-1669643354985)(1669384312153.png)]

注意:
在涉及到文件上传的操作时,必须将enctype的值设置为multipart/form-data

如果表单的提交不涉及到文件上传操作,则直接将enctype的值设置为application/x-www-form-urlencoded即可

(4)表单的同步提交及缺点

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

1)表单提交的缺点

form表单同步提交后,整个页面会发生跳转,跳转到action URL所指向的地址,用户体验很差。

form表单同步提交后,页面之前的状态和数据会丢失。

2)解决缺点

解决方案:表单只负责采集数据,Ajax负责将数据提交到服务器。(阻止表单默认提交行为)

2、通过Ajax提交表单数据

1)监听表单提交事件

在jQuery中,可以使用如下两种方式,监听到表单的提交事件:

    <form action="/login" id="f1">
        <input type="text" name="user_name" />
        <input type="password" name="password" />
        <button type="submit">提交</button>
    </form>

    <script>
        $(function (){
        //    1、获取表单 调用.submit函数
            /*$('#f1').submit(function (){
                alert('监听到了表单提交事件1')
            })*/
        //    2、.on('submit') 调用.on函数,绑定submit事件
            $('#f1').on('submit',function (){
                alert('监听到了表单的提交事件2')
            })
        })
    </script>
2)阻止表单的默认提交行为

点击提交之后的页面跳转行为就是表单的默认提交行为

当监听到表单的提交事件以后,可以调用事件对象的**event.preventDefault()**函数,来阻止表单的提交和页面的跳转,示例代码如下:

<form action="/login" id="f1">
    <input type="text" name="user_name" />
    <input type="password" name="password" />
    <button type="submit">提交</button>
</form>

<script>
    $(function (){
    //    1、阻止默认提交行为及页面跳转
        /*$('#f1').submit(function (e){
            alert('监听到了表单的提交事件')
            e.preventDefault()
        })*/
    //    2、阻止默认提交行为及页面跳转
        $('#f1').on('submit',function (e){
            alert('监听到了表单的提交事件2')
            e.preventDefault()
        })
    })
</script>
3)快速获取表单中的数据serialize()

serialize函数

为了简化表单中数据的获取操作,jQuery提供了serialize()函数,其语法格式如下:

$(selector).serialize()
//返回值:name属性=值&name属性=值

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

注意:在使用serialize)函数快速获取表单数据时,必须为每个表单元素添加name 属性!

<!--在使用serialize)函数快速获取表单数据时,必须为每个表单元素添加name 属性!-->
  <form action="/login" id="f1">
    <input type="text" name="user_name" />
    <input type="password" name="password" />
    <button type="submit">提交</button>
  </form>
<script>
  $(function (){
    //1、
    /*$('#f1').submit(function (e){
       e.preventDefault()
       var data = $(this).serialize()
      //返回值:name属性=值&name属性=值
      console.log(data)  //user_name=12w&password=qqe
       })*/
    //    2、
    $('#f1').on('submit',function (e){
      e.preventDefault()
      var data = $(this).serialize()
      console.log(data) //user_name=qwqw&password=xzd
    })
  })
</script>

3、案例-评论列表

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
  <link rel="stylesheet" href="lib/bootstrap.css" />
  <script src="lib/jquery.js"></script>
  <script src="js/cmt.js"></script>
</head>

<body style="padding: 15px;">

  <!-- 评论面板 -->
  <div class="panel panel-primary">
    <div class="panel-heading">
      <h3 class="panel-title">发表评论</h3>
    </div>
    <form class="panel-body" id="formAddCmt">
      <div>评论人:</div>
      <input type="text" class="form-control" name="username" autocomplete="off" />
      <div>评论内容:</div>
      <textarea class="form-control" name="content"></textarea>

      <button type="submit" class="btn btn-primary">发表评论</button>
    </form>
  </div>


  <!-- 评论列表 -->
  <ul class="list-group" id="cmt-list">
    <li class="list-group-item">
<!--      评论时间写在上面先浮动,紧贴右边,评论人后浮动,贴着评论时间-->
      <span class="badge" style="background-color: #F0AD4E;">评论时间:</span>
      <span class="badge" style="background-color: #5BC0DE;">评论人:</span>
      第一条测试评论1
    </li>
  </ul>

</body>

</html>
$(function (){
  function getCommentList(){
    $.ajax({
      method:'GET',
      url:'http://www.liulongbin.top:3006/api/cmtlist',
      data:{},
      success:function (res){
        if (res.status !== 200){
          return alert('获取评论列表失败')
        }
        // console.log(res)
        var rows = []
        $.each(res.data,function (i,item){
          var str = '<li class="list-group-item"><span class="badge" style="background-color: #F0AD4E;">评论时间:'+ item.time+'</span><span class="badge" style="background-color: #5BC0DE;">评论人:'+ item.username+'</span>'+ item.content+'</li>'
          rows.push(str)
        })
        //join方法用于把数组中的所有元素放入一个字符串。元素是通过指定的分隔符进行分隔的。
        //大白话:join方法可以用符不同的分隔符来构建这个字串。join方法值接受一个参数,
        // 即用作分隔符的字符串,然后返回所有数组项的字符串。
        $('#cmt-list').empty().append(rows.join(''))
      }
    })
  }
  getCommentList()


//  发表评论
  $('#formAddCmt').submit(function (e){
    e.preventDefault()
    var data = $(this).serialize()
    $.ajax({
      method:'POST',
      url:'http://www.liulongbin.top:3006/api/addcmt',
      data:data,
      success:function (res){
        if (res.status !== 201){
          return alert('发送评论失败')
        }
        getCommentList()
        //$('#formAddCmt')[0]把jqury对象转换为原生dom对象,这样就可以调用原生dom中的reset重置表单
        $('#formAddCmt')[0].reset()
      }
    })
  })
})

4、模板引擎的基本概念

1)渲染UI结构时遇到的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5cL163KU-1669643354986)(1669447667090.png)]

上述代码是通过字符串拼接的形式,来渲染UI结构。

如果UI结构比较复杂,则拼接字符串的时候需要格外注意引号之前的嵌套。且一旦需求发生变化,修改起来也非常麻烦。

2)什么是模板引擎

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

3)模板引擎的好处
  • 减少了字符串的拼接操作
  • 使代码结构更加清晰
  • 使代码更易于阅读和维护

5、art-template模板引擎

(1)art-template简介

art-template是一个简约、超快的模板引擎。

中文官网首页为http://aui.github.io/art-template/zh-cn/index.html

去官网下载,并通过script标签加载到网页上进行使用

(2)基本使用

1)使用传统方式渲染UI结构
<div id="title"></div>
<div>姓名:<span id="name"></span></div>
<div>年龄:<span id="age"></span></div>
<div>会员:<span id="isVIP"></span></div>
<div>注册时间:<span id="regTime"></span></div>
<div>爱好:
  <ul id="hobby">
    <li>爱好1</li>
    <li>爱好2</li>
  </ul>
</div>

<script>
  var data = {
    title: '<h3>用户信息</h3>',
    name: 'zs',
    age: 20,
    isVIP: true,
    regTime: new Date(),
    hobby: ['吃饭', '睡觉', '打豆豆']
  }


  $(function () {
    $('#name').html(data.name)
    $('#title').html(data.title)
    $('#age').html(data.age)
    $('#isVIP').html(data.isVIP)
    $('#regTime').html(data.regTime)

    var rows = []
    $.each(data.hobby, function (i, item) {
      rows.push('<li>' + item + '</li>')
    })
    $('#hobby').html(rows.join(''))
  })
</script>

2)art-template使用步骤

导入art-template、定义数据、定义模板、调用template函数、渲染HTML结构

  <!-- 1. 导入模板引擎 -->
  <!-- 在 window 全局,多一个函数,叫做 template('模板的Id', 需要渲染的数据对象) -->
  <script src="lib/template-web.js"></script>
  <script src="lib/jquery.js"></script>
</head>

<body>

  <div id="container"></div>

  <!-- 3. 定义模板 -->
  <!-- 3.1 模板的 HTML 结构,必须定义到 script 中 -->
<!--3.2 script标签如果不指定type属性的话,默认是text/javascript 意思是将标签里的所有代码都当成js代码去解析执行,
但这里是模板,需要有html代码,所以设置type="text/html"
这里给script标签设置的id是template函数的第一个参数-->
  <script type="text/html" id="tpl-user">
<!--3.3 双括号{{}}是模板引擎提供的语法,相当于占位符,代表这里将来要填充的数据-->
    <h1>{{name}}    ------    {{age}}</h1>
  </script>
  <script>
    // 2. 定义需要渲染的数据
    var data = { name: 'zs', age: 20}

    // 4. 调用 template 函数 两个参数,(模板id,需要渲染的数据)
    //这里不是jquery,是模板引擎,所以不需要加#号
    var htmlStr = template('tpl-user', data)
    console.log(htmlStr)
    // 5. 渲染HTML结构
    $('#container').html(htmlStr)
  </script>
</body>

3)art-template标准语法

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

1> 输出

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

{{value}}
{{obj.key}}
{{obj['key']}}
{{a ? b : c}}
{{a || b}}
{{a + b}}

2> 原文输出

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

{{@ value}}

3> 条件输出

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

  • if 代表条件输出的开始
  • else if 代表其他判断条件条件
  • /if 代表条件输出的结束
{{if value}}按需输出的内容{{/if}}

{{if v1}}按需输出的内容{{else if v2}}按需输出的内容{{/if}}

4> 循环输出

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

{{each arr}}

{{$index}} {{$value}}

{{/each}}

5> 过滤器

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGY4bSJc-1669643354987)(1669450977568.png)]

{{value | fiterName}}
|表示调用一个函数,vaue是值,filterName是一个函数,需要把value当成参数传进filterName函数里,返回一个新值

过滤器语法类似管道操作符,它的上一个输出作为下一个输入。

定义过滤器的语法:

template.defaults.imports.filterName = function(value){ /*return处理的结果*/}

  <!-- 1. 导入模板引擎 -->
  <!-- 在 window 全局,多一个函数,叫做 template('模板的Id', 需要渲染的数据对象) -->
  <script src="lib/template-web.js"></script>
  <script src="lib/jquery.js"></script>
</head>

<body>

  <div id="container"></div>

  <!-- 3. 定义模板 -->
  <!-- 3.1 模板的 HTML 结构,必须定义到 script 中 -->
<!--3.2 script标签如果不指定type属性的话,默认是text/javascript 意思是将标签里的所有代码都当成js代码去解析执行,
但这里是模板,需要有html代码,所以设置type="text/html"
这里给script标签设置的id是template函数的第一个参数-->
  <script type="text/html" id="tpl-user">
<!--3.3 双括号{{}}是模板引擎提供的语法,相当于占位符,代表这里将来要填充的数据-->
<!--输出-->
    <h1>{{name}}    ------    {{age}}</h1>
<!--原文输出-->
    {{@ test}}

<!--条件输出-->
    <div>
      {{if flag === 0}}
      flag的值是0
      {{else if flag === 1}}
      flag的值是1
      {{/if}}
    </div>

<!--循环输出-->
    <ul>
      {{each hobby}}
      <li>索引是{{$index}},循环项是{{$value}}</li>
      {{/each}}
    </ul>

<!--过滤器-->
    <h3>{{regTime | dateFormat}}</h3>
  </script>

  <script>
    // 定义处理时间的过滤器
    template.defaults.imports.dateFormat = function (date) {
      var y = date.getFullYear()
      var m = date.getMonth() + 1
      var d = date.getDate()
      //注意:过滤器最后一定要return一个值
      return y + '-' + m + '-' + d
    }

    // 2. 定义需要渲染的数据
    var data = { name: 'zs', age: 20, test: '<h3>测试原文输出</h3>', flag: 1, hobby: ['吃饭', '睡觉', '写代码'], regTime: new Date() }

    // 4. 调用 template 函数 两个参数,(模板id,需要渲染的数据)
    //这里不是jquery,是模板引擎,所以不需要加#号
    var htmlStr = template('tpl-user', data)
    console.log(htmlStr)
    // 5. 渲染HTML结构
    $('#container').html(htmlStr)
  </script>
</body>

(3)新闻列表案例

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
  <link rel="stylesheet" href="assets/news.css" />
  <script src="lib/jquery.js"></script>
  <script src="lib/template-web.js"></script>
  <script src="js/news.js"></script>
</head>

<body>

  <div id="news-list">

  </div>

  <!-- 定义模板 -->
<script type="text/html" id="tpl-news">
<!--  {{data.length}}-->
{{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">
<!--        这个$value是新闻的每一项,循环新闻tags数组的每一项-->
        {{each $value.tags}}
<!--        这个$value是新闻的tags数组的每一项-->
        <span>{{$value}}</span>
        {{/each}}
      </div>
      <div class="footer">
        <div>
          <span>{{$value.source}}</span>&nbsp;&nbsp;
          <span>{{$value.time | dataFormat}}</span>
        </div>
        <span>评论数:{{$value.cmtcount}}</span>
      </div>
    </div>
  </div>
  {{/each}}
</script>

</body>

</html>

$(function (){
// 获取新闻数据
// 定义template模板编译模板
// 定义时间过滤器
// 定义补零函数
  //获取新闻列表的函数
  function getNewsList(){
    $.ajax({
      method:'GET',
      url:'http://www.liulongbin.top:3006/api/news',
      data:{},
      success:function (res){
        if (res.status !== 200) return alert('获取新闻列表失败')
        console.log(res)
        for (var i = 0;i<res.data.length;i++){
          //把每一项的tags属性,从字符串改造成字符串的数组
          res.data[i].tags = res.data[i].tags.split(',')
        }
        var htmlStr = template('tpl-news',res)
        //渲染html结构
        $('#news-list').html(htmlStr)
      }
    })
  }
  getNewsList()

//  定义格式化时间的过滤器
  template.defaults.imports.dataFormat = function (dtstr){
    var dt = new Date(dtstr)
    var y = dt.getFullYear()
    //调用补0函数 年份不需要
    var m = padZero(dt.getMonth())
    var d = padZero(dt.getDate())

    var hh = padZero(dt.getHours())
    var mm = padZero(dt.getMinutes())
    var ss = padZero(dt.getSeconds())
    return y + '-' + m + '-' + d +' ' + hh + ' : ' + mm + ' : ' + ss
  }

//  补0函数
  function padZero(n){
    //给时间补充0
    if (n<10){
      return '0' + n
    }else{
      return  n
    }
  }
})

6、模板引擎的实现原理

(1)正则与字符串操作

1)基本语法

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

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

<script>
  var str = 'hello'
  var pattern = /x/

  var result = pattern.exec(str)
  console.log(result)
</script>

2)分组

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

<script>
  var str = '<div>我是{{name}}</div>'
  //\s是空格 *是任意多个
  // 正则表达式中()包起来的内容表示一个分组,可以通过分组来提取自己想要的内容
  var pattern = /{{([a-zA-Z]+)}}/

  //记住重点,从exec匹配的结果中提取用小括号分组的值
  var result = pattern.exec(str)
  //输出结果的数组中的第一个元素 '{{name}}' 表示匹配到的内容;第二个元素 'name' 表示将内容提取出来了,前面正则中加了()才能提取。
  console.log(result) //['{{name}}', 'name', index: 7, input: '<div>我是{{name}}</div>', groups: undefined]
//  index:7 是因为{{name}}的第一个是{,在字符串<div>我是{{name}}</div>中,索引是7
</script>

3)字符串的replace函数

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

<script>
  var str = '<div>我是{{name}}</div>'
  //提取分组
  var pattern = /{{([a-zA-Z]+)}}/

  var result = pattern.exec(str)
  console.log(result) //['{{name}}', 'name', index: 7, input: '<div>我是{{name}}</div>', groups: undefined]
  str = str.replace(result[0],result[1])
  console.log(str) //<div>我是name</div>
</script>

4)多次replace
<script>
  var str = '<div>{{name}}今年{{ age }}岁了</div>'
  //\s是空格 *是任意多个
  var pattern = /{{\s*([a-zA-Z]+)\s*}}/

  // 第一次匹配  提取--》replace替换
  var result1 = pattern.exec(str)
  str = str.replace(result1[0],result1[1])
  console.log(str) //<div>name今年{{ age }}岁了</div>

  // 第二次匹配
  var result2 = pattern.exec(str)
  str = str.replace(result2[0],result2[1])
  console.log(str) //<div>name今年age岁了</div>

  // 第三次匹配
  var result3 = pattern.exec(str)
  console.log(result3) //null
</script>

5)简化-使用while循环replace
<script>
  var str = '<div>{{name}}今年{{ age }}岁了</div>'
  var pattern = /{{\s*([a-zA-Z]+)\s*}}/

  var result = null
  //注意,括号里是把pattern.exec(str)赋值给了result
  //当最后一次pattern.exec(str)返回为null时,括号里的值为false就退出循环
  while(result = pattern.exec(str)){
    str = str.replace(result[0],result[1])
  }
  console.log(str) //<div>name今年age岁了</div>

</script>

6)replace替换为真值(核心)
<script>
<!--  模板引擎的核心原理-->
  var data = {name:'lisi',age:18}
  var str = '<div>{{name}}的年龄是{{ age }}岁</div>'
  var pattern = /{{\s*([a-zA-Z]+)\s*}}/

  var result = null
  while(result = pattern.exec(str)){
    //把str的替换成data里的值,data属性为result【1】的值
    str = str.replace(result[0],data[result[1]])
  }
  console.log(str) //<div>lisi的年龄是18岁</div>
</script>

(2)实现简易的模板引擎(重要)

步骤

  • 定义模板结构
  • 预调用模板引擎
  • 封装template函数
  • 导入并使用自定义的模板引擎
  <script src="template.js"></script>
</head>
<body>
<div id="user-box"></div>
<!--1、定义模板结构-->
<script type="text/html" id="tpl-user">
  <div>姓名:{{name}}</div>
  <div>年龄:{{  age}}</div>
  <div>性别:{{ sex}}</div>
  <div>住址:{{address  }}</div>
</script>

<script>
  <!--2、预调用模板引擎-->
  //定义数据
  var data = {name:'zs',age:19,sex:'男',address:'北京'}
//  调用模板引擎
  var htmlStr = template('tpl-user',data)
//  渲染html页面
  document.getElementById('user-box').innerHTML = htmlStr
</script>
</body>

//template.js
// 封装模板
function template(id,data){
  //先拿到模板结构
  var str = document.getElementById(id).innerHTML
  var pattern = /{{\s*([a-zA-Z]+)\s*}}/
  //进入循环匹配,每次匹配都将匹配的字符串替换成data里真实的数据
  var result = null
  while(result = pattern.exec(str)){
    str = str.replace(result[0],data[result[1]])
  }
  //最后把拿到的str return出去,让调用的可以接收 var htmlStr = template('tpl-user',data)
  return str
}

Ajax加强

1、XMLHttpRequest的基本使用

(1)什么是XMLHttpRequest

XMLHttpRequest(简称xhr)是浏览器提供的Javascript对象,通过它,可以请求服务器上的数据资源。之前所学的jQuery中的 Ajax函数,就是基于xhr对象封装出来的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2GSssRl4-1669643354988)(1669512677099.png)]

(2)使用xhr发起GET请求

步骤:

  • 创建xhr对象
  • 调用xhr.open()函数 创建请求
  • 调用xhr.send()函数 发起请求
  • 监听xhr.onreadystatechange事件 可以拿到服务器响应回来的数据
<script>
  //1、创建xhr对象
  var xhr = new XMLHttpRequest()
//  2、调用open函数创建一个请求 open('请求方式','url地址')
  xhr.open('GET','http://www.liulongbin.top:3006/api/getbooks')
//  3、调用send函数发起ajax请求
  xhr.send()
//  4、监听 onreadystatechange 事件
  xhr.onreadystatechange = function (){
    //括号里的判断条件是固定写法,条件成立说明有数据,可以通过xhr.responseText获取到数据
    //监听xhr对象的请求状态 readyStatus;与服务器响应的状态status
    if (xhr.readyState === 4 && xhr.status === 200){
    //  获取服务器响应的数据
      console.log(xhr.responseText)//这个输出数据里有一个status是数据的一部分,上面判断条件里的status是响应状态,两个不一样
    }
  }
</script>

(3)了解xhr对象的readyState属性

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

状态描述
0UNSENTXMLHttpRequest对象已被创建,但尚未调用open方法。
1OPENEDopen()方法已经被调用。
2HEADERS_RECEIVEDsend()方法已经被调用,响应头也已经被接收。
3LOADING数据接收中,此时response属性中已经包含部分数据。
4DONEAjax请求完成,这意味着数据传输已经彻底完成或失败。

(4)使用xhr发起带参数的get请求

使用xhr对象发起带参数的GET请求时,只需在调用xhr.open期间,为URL地址指定参数即可

这种在 URL地址后面拼接的参数,叫做查询字符串。

<script>
  //1、创建xhr对象
  var xhr = new XMLHttpRequest()
  //2、创建请求
  //?代表为这次请求提供参数,以键值对的形式传参
  //这种在 URL地址后面拼接的参数,叫做查询字符串。
  xhr.open('GET','http://www.liulongbin.top:3006/api/getbooks?id=1')
  //3、发起请求
  xhr.send()
//  4、监听事件
  xhr.onreadystatechange = function (){
    if (xhr.readyState === 4 && xhr.status === 200){
      console.log(xhr.responseText)
    }
  }
</script>

(5)查询字符串

1)什么是查询字符串

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

格式:英文的?放在URL的末尾,然后再加上参数=值,想加上多个参数的话,使用**&符号进行分隔**。以这个形式,可以将想要发送给服务器的数据添加到URL中。

//不带参数的URL地址
http://wwnw.liulongbin.top:3006/api/getbooks
//带一个参数的URL地址
http://wwnw.liulongbin.top:3006/api/getbooks?id=1
//带两个参数的URL地址
http://wwnw.liulongbin.top:3006/api/getbooks?id=1&bookname=西游记

2)get请求携带参数的本质

无论使用 . a j a x ( ) , 还 是 使 用 .ajax(),还是使用 .ajax()使.get(),又或者直接使用xhr对象发起GET请求,当需要携带参数的时候,本质上,都是直接将参数以查询字符串的形式,追加到URL地址的后面,发送到服务器的

$.get('url',{name:'zs',age:20),function () {})
//等价于
s.get('url?name=zs&age=20',function(){})
$.ajax({method:'GET',url:'url',data: {name: 'za',age: 20},success: function(){} })
//等价于
$.ajax ({ method: 'GET',url: 'url?name=zs&age=20 ',success: function(){}})

<script>
  //本质上,都是直接将参数以查询字符串的形式,追加到URL地址的后面,发送到服务器的。
  /*$.get('http://www.liulongbin.top:3006/api/getbooks', { id: 1, bookname: '西游记' }, function (res) {
    console.log(res)
  })*/

  $.ajax({
    method: 'GET',
    url: 'http://www.liulongbin.top:3006/api/getbooks',
    data: {
      id: 1,
      bookname: '西游记'
    },
    success: function (res) {
      console.log(res)
    }
  })
</script>

(6)URL编码与解码

1)什么是URL编码

URL地址中,只允许出现英文相关的字母、标点符号、数字,因此,在URL地址中不允许出现中文字符。

如果 URL中需要包含中文这样的字符,则必须对中文字符进行编码(转义).

**URL编码的原则:**使用安全的字符(没有特殊用途或者特殊意义的可打印字符)去表示那些不安全的字符。

URL编码原则的通俗理解:使用英文字符去表示非英文字符。

每一个中文字符编译成英文字符,都是三组百分号%

http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=西
//经过URL编码后,URL地址变成了如下格式
http://www.liulongbin.top:3006/api/getbooks?id=1&bookname=%E8%A5%BF%E6%B8%B8==%E8%AE%B0==

2)如何对URL进行编码和解码

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

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

<script>
  var str = '黑马程序员'
  var str2 = encodeURI(str)
  console.log(str2) //%E9%BB%91%E9%A9%AC%E7%A8%8B%E5%BA%8F%E5%91%98

  console.log('----------')
  var str3 = decodeURI('%E9%BB%91%E9%A9%AC')
  console.log(str3) //黑马
</script>

3)URL编码的注意事项

由于浏览器会自动对URL地址进行编码操作,因此,大多数情况下,程序员不需要关心URL地址的编码与解码操作。

关于URL编码的知识:https://blog.csdn.net/Lxd_0111/article/details/78028889

(7)使用xhr发起post请求

步骤:

  • 创建xhr对象
  • 调用xhr.open()函数
  • 设置Content-Type 属性(固定写法)
  • 调用xhr.send()函数,同时指定要发送的数据(以查询字符串的形式提交)
  • 监听xhr.onreadystatechange 事件
<script>
  //1、创建xhr对象
  var xhr = new XMLHttpRequest()
  //2、调用open创建请求 指定请求方式和url地址
  xhr.open('POST','http://www.liulongbin.top:3006/api/addbook')
//  3、设置content-type属性(固定写法)  重要
  xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
//  4、调用send() 同时将数据以查询字符串的形式,提交给服务器  重要
  xhr.send('bookname=水浒传&author=施耐庵&publisher=上海出版社')
//  5、监听onreadystatechange事件
  xhr.onreadystatechange = function (){
    if (xhr.readyState === 4 && xhr.status === 200){
      console.log(xhr.responseText) //{"status":201,"msg":"添加图书成功"}
    }
  }
</script>

2、数据交换格式

(1)什么是数据交换格式

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

前端领域,经常提及的两种数据交换格式分别是XML和JSON。其中XML用的非常少,所以,我们重点要学习的数据交换格式就是JSON.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Tp9NHQyC-1669643354989)(1669518522107.png)]

(2)XML

1)什么是XML

XML的英文全称是EXtensible Markup Language,即**可扩展标记语言。**因此,XML和HTML类似,也是一种标记语言。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tSAVnKN1-1669643354989)(1669518634175.png)]

2)XML与HTML的区别

XML和HTML虽然都是标记语言,但是,它们两者之间没有任何的关系。

  • HTML被设计用来描述网页上的内容,是网页内容的载体
  • XML被设计用来传输和存储数据,是数据的载体

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yqKnhyqz-1669643354990)(1669518773399.png)]

3)XML的缺点

① XML格式臃肿,和数据无关的代码多,体积大,传输效率低

② 在Javascript中解析XML比较麻烦

(3)JSON

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

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

1)什么是JSON

概念:JSON的英文全称是JavaScript Object Notation,即**“JavaScript对象表示法”。简单来讲,JSON就是Javascript对象和数组的字符串表示法,它使用文本表示一个JS对象或数组的信息,因此JSON的本质是字符串。**

作用:JSON是一种轻量级的文本数据交换格式,在作用上类似于XML,专门用于存储和传输数据,但是JSON比 XML更小、更快、更易解析。

现状:JSON是在2001年开始被推广和使用的数据格式,到现今为止,JSON已经成为了主流的数据交换格式。

2)JSON的两种结构

JSON就是用字符串来表示Javascript 的对象和数组。所以,JSON中包含对象和数组两种结构,通过这两种结构的相互嵌套,可以表示各种复杂的数据结构。

==对象结构:==对象结构在JSON 中表示为{}括起来的内容。数据结构为{ key:value, key: value …}的键值对结构。其中,key必须是使用英文的双引号包裹的字符串,value的数据类型可以是数字、字符串、布尔值、null、数组、对象6种类型。

**注意:**在JSON中,所有的字符串必须使用双引号来包裹,不能使用单引号。

​ 不包含undefined和function

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-86IVmwvT-1669643354990)(1669519413940.png)]

==数组结构:==数组结构在JSON 中表示为[]括起来的内容。数据结构为[“java” , “javascript”,30, true … ] 数组中数据的类型可以是数字、字符串、布尔值、null、数组、对象6种类型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lUQscGAV-1669643354991)(1669519593379.png)]

3)JSON语法的注意事项
  • 属性名必须使用双引号包裹
  • 字符串类型的值必须使用双引号包裹
  • JSON中不允许使用单引号表示字符串
  • JSON中不能写注释
  • JSON的最外层必须是对象或数组格式
  • 不能使用undefined 或函数作为JSON的值
4)JSON和JS对象的关系

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

//这是一个对象
var obj = {a: 'Hello',b: 'world' }
//这是一个对象结构的JSON字符串,本质是一个字符串
var json = '{ "a":"Hello","b":"world"}'

5)JSOn和JS对象的互转

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

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

<script>
  //1、把json字符串转换为js对象 JSON.parse()
  var jsonStr = '{"a":"hello","b":"world"}'
  var jsObj = JSON.parse(jsonStr)
  console.log(jsObj) //{a: 'hello', b: 'world'}

//  2、把JS对象转换为JSON字符串,使用JSON.stringify()
  var jsObj2 = {a:'abc',b:'you',c:false}
  var jsonStr2 = JSON.stringify(jsObj2)
  console.log(jsonStr2) //{"a":"abc","b":"you","c":false}
  console.log(typeof jsonStr2) //string
</script>

<script>
  /*应用场景:
  * 服务器响应一些数据之后,数据是JSON格式的字符串,就可以使用JSON.parse()将字符串转换为js对象之后再进一步操作
  * */
  //创建xhr对象
  var xhr = new XMLHttpRequest()
  //创建请求
  xhr.open('GET','http://www.liulongbin.top:3006/api/getbooks')
  //发送请求
  xhr.send()
  //监听事件
  xhr.onreadystatechange = function (){
    if (xhr.readyState === 4 && xhr.status === 200){
      console.log(xhr.responseText) //这里返回的是一个JSON字符串
      console.log(typeof xhr.responseText) //string
      var result = JSON.parse(xhr.responseText)
      console.log(result) //返回js对象
    }
  }
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cCNBn3Qo-1669643354991)(1669521350668.png)]

6)序列化和反序列化

把数据对象转换为字符串的过程,叫做序列化,例如:调用JSON.stringify() 函数的操作,叫做JSON序列化。

把字符串转换为数据对象的过程,叫做反序列化,例如:调用**JSON.parse()**函数的操作,叫做JSON反序列化。

3、封装自己的Ajax函数

最核心的还是创建xhr对象、调用open()创建请求、调用send()发送请求、监听事件获取数据。只不过多了要把调用函数输入的数据转换成查询字符串的格式提交给服务器,然后最后把xhr.responseText返回的JSON字符串转换成js对象即可

(1)要实现的效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ITK086op-1669643354992)(1669521687413.png)]

(2)定义options参数选项

itheima()函数是我们自定义的 Ajax函数,它接收一个配置对象作为参数,配置对象中可以配置如下属性:

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

(3)处理data参数

需要把 data对象,转化成查询字符串的格式,从而提交给服务器,因此提前定义resolveData函数如下

//需要把 data对象,转化成查询字符串的格式,从而提交给服务器,因此提前定义resolveData函数如下
//定义空数组--》遍历传过来的对象--》字符串以值=属性的方式拼接--》用&分隔每一个值
function resolveData(data){
  var arr = []
  for (var k in data){
    var str = k + '=' + data[k]
    arr.push(str)
  }
  return arr.join('&')
}
//接收return过来的数据
var res = resolveData({name:'zs',age:19})
console.log(res) //name=zs&age=19

  <script src="js/itheima.js"></script>
</head>
<body>

</body>

(4)定义itheima函数

在itheima()函数中,需要创建xhr对象,并监听onreadystatechange事件:

//2、封装itheima函数
function itheima(options){
  var xhr = new XMLHttpRequest()
  //把外界接收过来的参数对象,转化为查询字符串
  var qs = resolveData(options.data)
//  监听onreadystatechange事件
  xhr.onreadystatechange = function (){
    if (xhr.readyState === 4 && xhr.status === 200){
      //xhr.responseText返回的是json字符串,需要转换为js对象,
      var result = JSON.parse(xhr.responseText)
      //调用success函数
      options.success(result)
    }
  }
}

(5)判断请求类型

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

//判断请求方式
  if (options.method.toUpperCase() === 'GET'){
    //发起get请求 这里options.method可以直接写'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)
  }

最终代码🌓

  <script src="js/itheima.js"></script>
</head>
<body>
<script>
  //调用函数发起get请求
  itheima({
    method:'GET',
    url:'http://www.liulongbin.top:3006/api/getbooks',
    data:{
      // id:1
    },
    success:function (res){
      console.log(res)
    }
  })
  //调用函数发起post请求
  /*itheima({
    method:'POST',
    url:'http://www.liulongbin.top:3006/api/addbook',
    data:{
      bookname:'活着',
      author:'余华',
      publisher:'北京出版社'
    },
    success:function (res){
      console.log(res)
    }
  })*/
</script>
</body>

//1、把 data对象,转化成查询字符串的格式,从而提交给服务器,因此提前定义resolveData函数如下
//定义空数组--》遍历传过来的对象--》字符串以值=属性的方式拼接--》用&分隔每一个值
function resolveData(data){
  var arr = []
  for (var k in data){
    var str = k + '=' + data[k]
    arr.push(str)
  }
  return arr.join('&')
}
/*
//接收return过来的数据
var res = resolveData({name:'zs',age:19})
console.log(res) //name=zs&age=19*/

//2、封装itheima函数
function itheima(options){
  var xhr = new XMLHttpRequest()
  //把外界接收过来的参数对象,转化为查询字符串
  var qs = resolveData(options.data)

//3、判断请求方式
  if (options.method.toUpperCase() === 'GET'){
    //发起get请求 这里options.method可以直接写'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)
  }

//  监听onreadystatechange事件
  xhr.onreadystatechange = function (){
    if (xhr.readyState === 4 && xhr.status === 200){
      //xhr.responseText返回的是json字符串,需要转换为js对象,
      var result = JSON.parse(xhr.responseText)
      //调用success函数
      options.success(result)
    }
  }
}

4、XMLHttpRequest Level2的新特性

(1)认识Level2

1)旧版XMLHttpRequest的缺点
  • 只支持文本数据的传输。无法用来读取和上传文件
  • 传送和接收数据时,没有进度信息,只能提示有没有完成
2)Level2 的新功能
  • 可以设置HITP请求的时限
  • 可以使用FormData对象管理表单数据
  • 可以上传文件
  • 可以获得数据传输的进度信息

(2)设置Http请求时限

有时,Ajax操作很耗时,而且无法预知要花多少时间。如果网速很慢,用户可能要等很久。新版本的XMLHttpRequest对象,增加了 timeout属性,可以设置HTTP请求的时限

xhr.timeout = 3000

上面的语句,将最长等待时间设为3000毫秒。过了这个时限,就自动停止HTTP请求。与之配套的还有一个timeout事件,用来指定回调函数

xhr.ontimeout = function(event){
    alert('请求超时')
}

<script>
  var xhr = new XMLHttpRequest()
//  设置超时时限 单位毫秒
  xhr.timeout = 30
  //设置超时后的处理函数
  xhr.ontimeout = function (){
    console.log('请求超时')
  }
  xhr.open('GET','http://www.liulongbin.top:3006/api/getbooks')
  xhr.send()
  xhr.onreadystatechange = function (){
    if (xhr.readyState === 4 && xhr.status === 200){
      console.log(xhr.responseText)
    }
  }
</script>

(3)FormData对象管理表单数据

1)模拟表单操作

Ajax操作往往用来提交表单数据。为了方便表单处理,HTMLS新增了一个FormData对象,可以模拟表单操作:

<script>
    //1、创建FormData实例
    var fd = new FormData()
//    2、调用append函数,向fd中追加数组
    fd.append('uname','zs')
    fd.append('upwd','123456')
    var xhr = new XMLHttpRequest()
    xhr.open('POST','http://www.liulongbin.top:3006/api/formdata')
    // 好像是新版的直接把post请求的header封装了,所以不写header也没问题,要不会报错的
    //也有可能是加了这个代码数据会加密
    //设置Content-Type ,  这一步是为了模拟表单提交 也就是?''=''&,这种,以便于服务器读取数据,如果服务器写了读取原始post数据的逻辑,也可以不加这段,
    // xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded')
    //3、直接提交FormData对象,与提交网页表单的效果完全一样
    xhr.send(fd)
    xhr.onreadystatechange = function (){
        if (xhr.readyState === 4 && xhr.status === 200){
            console.log(JSON.parse(xhr.responseText))
        }
    }
</script>

2)获取网页表单的值

FormData对象也可以用来获取网页表单的值

<form action="" id="form1">
<!--  autocomplete="off"阻止自动填充效果-->
  <input type="text" name="uname" autocomplete="off" />
  <input type="password" name="upwd"/>
  <button type="submit">提交</button>
</form>
<script>
  //1、通过dom操作,拿到form表单元素
  var form = document.getElementById('form1')
  form.addEventListener('submit',function (e){
  //  阻止默认提交行为
    e.preventDefault()
    //2、创建formdata,快速获取form表单中的数据
    var fd = new FormData(form)
  //  发送请求
    var xhr = new XMLHttpRequest()
    xhr.open('post','http://www.liulongbin.top:3006/api/formdata')
    //3、将fd数据发送到服务器
    xhr.send(fd)
    xhr.onreadystatechange = function (){
      if (xhr.readyState === 4 && xhr.status === 200){
        console.log(JSON.parse(xhr.responseText))
      }
    }
  })
</script>

(4)上传文件

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

步骤:

  • 定义UI结构
  • 验证是否选择了文件
  • 向FormData中追加文件
  • 使用xhr’发起上传文件的请求
  • 监听onreadystatechange 事件
1)定义UI结构
<body>
<!--1、定义基本UI结构-->
  <!-- 1.1 文件选择框 -->
  <input type="file" id="file1" />
  <!-- 1.2 上传文件的按钮 -->
  <button id="btnUpload">上传文件</button>
  <br />
  <!-- 1.3 img 标签,来显示上传成功以后的图片 -->
  <img src="" alt="" id="img" width="800" />

</body>

2)验证是否上传了文件
<script>
  //2、验证是否选择了文件
  //2.1 获取文件上传按钮
  var btnUpload = document.querySelector('#btnUpload')
//  2.2 为按钮绑定点击事件处理函数
  btnUpload.addEventListener('click',function (){
  //  2.3 获取用户选择的文件列表 files是文件的数组
    var files = document.querySelector('#file1').files
    if (files.length <= 0){
      return alert('请选择要上传的文件')
    }
    console.log('用户选择了要上传的文件')
  })
</script>

3)向FormData中追加文件
//3、向FormData中追加文件
var fd = new FormData()
//将用户选择的文件,添加到FormData中
//'avatat'是属性,值是files[0],此时files中有数据,可以追加
fd.append('avatar',files[0])

4)使用xhr发起上传文件的请求
//  4、使用xhr发起上传文件的请求
//  创建xhr对象
  var xhr = new XMLHttpRequest()
  //这里请求方式必须为post
  xhr.open('post','http://www.liulongbin.top:3006/api/upload/avatar')
  //发起请求
  xhr.send(fd)

5)监听onreadystatechange 事件
//  5、监听onreadystatechange 事件
  xhr.onreadystatechange = function (){
    if (xhr.readyState === 4 && xhr.status === 200){
      var data = JSON.parse(xhr.responseText)
      // console.log(data)
      if (data.status === 200){
        //设置图片的src属性
        document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url
      }else{
        alert('上传文件失败' + data.message)
      }
    }
  }

最终代码🌗
<body>
<!--1、定义基本UI结构-->
  <!-- 1.1 文件选择框 -->
  <input type="file" id="file1" />
  <!-- 1.2 上传文件的按钮 -->
  <button id="btnUpload">上传文件</button>
  <br />
  <!-- 1.3 img 标签,来显示上传成功以后的图片 -->
  <img src="" alt="" id="img" width="800" />

  <script>
    //2、验证是否选择了文件
    //2.1 获取文件上传按钮
    var btnUpload = document.querySelector('#btnUpload')
  //  2.2 为按钮绑定点击事件处理函数
    btnUpload.addEventListener('click',function (){
    //  2.3 获取用户选择的文件列表 files是文件的数组
      var files = document.querySelector('#file1').files
      if (files.length <= 0){
        return alert('请选择要上传的文件')
      }
      // console.log('用户选择了要上传的文件')
      //3、向FormData中追加文件
      var fd = new FormData()
      //将用户选择的文件,添加到FormData中
      //'avatat'是属性,值是files[0],此时files中有数据,可以追加
      fd.append('avatar',files[0])

    //  4、使用xhr发起上传文件的请求
    //  创建xhr对象
      var xhr = new XMLHttpRequest()
      
        //监听文件上传进度xhr.upload.onprogress
        /*事件对象e有三个属性
        1、e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
        e-loaded:已传输的字节      e .total:需传输的总字节*/
        xhr.upload.onprogress = function (e){
            if (e.lengthComputable){
                //计算出上传的进度 ceil向上取整
                var procentComplete = Math.ceil((e.loaded/e.total)*100)
                console.log(procentComplete)
            }
        }

      //这里请求方式必须为post
    xhr.open('post','http://www.liulongbin.top:3006/api/upload/avatar')
      //发起请求
      xhr.send(fd)

    //  5、监听onreadystatechange 事件
      xhr.onreadystatechange = function (){
        if (xhr.readyState === 4 && xhr.status === 200){
          var data = JSON.parse(xhr.responseText)
          // console.log(data)
          if (data.status === 200){
            //设置图片的src属性
            document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url
          }else{
            alert('上传文件失败' + data.message)
          }
        }
      }
    })
  </script>
</body>

(5)显示文件的上传进度

新版本的XMLHttpRequest对象中,可以通过监听xhr.upload.onprogress事件,来获取到文件的上传进度。监听上传完成的事件xhr.upload.onload

//  4、使用xhr发起上传文件的请求
        var xhr = new XMLHttpRequest()

        //监听文件上传进度xhr.upload.onprogress
        /*事件对象e有三个属性
        1、e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
        e-loaded:已传输的字节      e .total:需传输的总字节*/
        xhr.upload.onprogress = function (e){
            if (e.lengthComputable){
                //计算出上传的进度 ceil向上取整
                var procentComplete = Math.ceil((e.loaded/e.total)*100)
                console.log(procentComplete)
                //动态设置进度条
                $('#percent').attr('style','width:' + procentComplete + '%').html(procentComplete + '%')
            }
        }
        //监听上传完成的事件
        xhr.upload.onload =function (){
            $('#percent').removeClass().addClass('progress-bar progress-bar-success')
        }

完整代码(有动态进度条)🌗

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="lib/bootstrap.css">
    <script src="lib/jquery.js"></script>
</head>

<body>
<!--1、定义基本UI结构-->
<input type="file" id="file1" />
<button id="btnUpload">上传文件</button>
<br />
<img src="" alt="" id="img" width="800" />

<!--bootstrap 中的进度条-->
<div class="progress" style="width: 500px; margin: 15px 10px;">
    <div class="progress-bar progress-bar-striped active" style="width: 0%" id="percent">
        0%
    </div>
</div>
<script>
    //2、验证是否选择了文件
    var btnUpload = document.querySelector('#btnUpload')
    btnUpload.addEventListener('click',function (){
        var files = document.querySelector('#file1').files
        if (files.length <= 0){
            return alert('请选择要上传的文件')
        }
        //3、向FormData中追加文件
        var fd = new FormData()
        fd.append('avatar',files[0])

        //  4、使用xhr发起上传文件的请求
        var xhr = new XMLHttpRequest()

        //监听文件上传进度xhr.upload.onprogress
        /*事件对象e有三个属性
        1、e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
        e-loaded:已传输的字节      e .total:需传输的总字节*/
        xhr.upload.onprogress = function (e){
            if (e.lengthComputable){
                //计算出上传的进度 ceil向上取整
                var procentComplete = Math.ceil((e.loaded/e.total)*100)
                console.log(procentComplete)
                //动态设置进度条
                $('#percent').attr('style','width:' + procentComplete + '%').html(procentComplete + '%')
            }
        }
        //监听上传完成的事件
        xhr.upload.onload =function (){
            $('#percent').removeClass().addClass('progress-bar progress-bar-success')
        }

        xhr.open('post','http://www.liulongbin.top:3006/api/upload/avatar')
        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){
                    document.querySelector('#img').src = 'http://www.liulongbin.top:3006' + data.url
                }else{
                    alert('上传文件失败' + data.message)
                }
            }
        }
    })
</script>
</body>
</html>

5、jQuery高级用法

  <script src="lib/jquery.js"></script>
</head>
<body>
<!--1、定义UI结构-->
<input type="file" id="filel" />
<button id="btnUpload">上传文件</button>

<script>
  $(function (){
    $('#btnUpload').on('click',function (){
      //2、验证是否选择了文件
      //$('#filel')[0]将jquery对象转换为dom对象,并获取选中的文件列表
      var files = $('#filel')[0].files
      if (files.length <= 0){
        return alert('请上传文件')
      }
      // console.log('文件已上传')
    //  3、向FormData中追加文件
      var fd = new FormData()
      fd.append('avatar',files[0])
    //  4、使用jQuery调用ajax发起上传文件的请求,这里只能使用ajax
      $.ajax({
        method:'POST',
        url:'http://www.liulongbin.top:3006/api/upload/avatar',
        data:fd,
        //不对FormData中的数据进行url 编码,而是将 FormData数据原样发送到服务器
        processData:false,
        //不修改content-Type属性,使用 FormData默认的 content-Type值
        contentType:false,
        success:function(res){
          console.log(res)
        }
      })
    })
  })

</script>
</body>

jQuery实现loading效果

1)ajaxStart(callback)

Ajax请求开始时,执行 ajaxStart 函数。可以在ajaxStart的callback中显示loading 效果,

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-orcVrrHU-1669643354993)(1669551329723.png)]

2)ajaxStop(callback)

Ajax请求结束时,执行 ajaxStop 函数。可以在 ajaxStop的callback 中隐藏loading效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pB8QxJqu-1669643354993)(1669551639789.png)]

  <script src="lib/jquery.js"></script>
</head>
<body>
<!--1、定义UI结构-->
<input type="file" id="filel" />
<button id="btnUpload">上传文件</button>
<img src="images/loading.gif" alt="" style="display: none" id="loading">

<script>
  $(function (){
    //监听到ajax请求被发起 添加loading
    $(document).ajaxStart(function (){
      $('#loading').show()
    })

    //监听到ajax完成的事件 隐藏loading
    $(document).ajaxStop(function (){
      $('#loading').hide()
    })

    $('#btnUpload').on('click',function (){
      //2、验证是否选择了文件
      //$('#filel')[0]将jquery对象转换为dom对象,并获取选中的文件列表
      var files = $('#filel')[0].files
      if (files.length <= 0){
        return alert('请上传文件')
      }
      // console.log('文件已上传')
    //  3、向FormData中追加文件
      var fd = new FormData()
      fd.append('avatar',files[0])
    //  4、使用jQuery调用ajax发起上传文件的请求,这里只能使用ajax
      $.ajax({
        method:'POST',
        url:'http://www.liulongbin.top:3006/api/upload/avatar',
        data:fd,
        //不对FormData中的数据进行url 编码,而是将 FormData数据原样发送到服务器
        processData:false,
        //不修改content-Type属性,使用 FormData默认的 content-Type值
        contentType:false,
        success:function(res){
          console.log(res)
        }
      })
    })
  })

</script>
</body>

6、axios(专注于网络数据请求)

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

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

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

(1)axios发起get请求

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

  <script src="lib/axios.js"></script>
</head>
<body>
  <button id="btn1">发起get请求</button>
  <script>
    var btn1 = document.querySelector('#btn1')
    btn1.addEventListener('click',function (){
      var url = 'http://www.liulongbin.top:3006/api/get'
      var paramObj = {name:'zs',age:20}
      //res有6个属性,是axios包装的,res.data是服务器返回的真实数据
      axios.get(url,{params:paramObj}).then(function (res){
        console.log(res)
        console.log(res.data)
      })
    })
  </script>
</body>

(2)axios发起post请求

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

//  2、发起post请求
  var btn2 = document.querySelector('#btn2')
  btn2.addEventListener('click',function (){
    var url = 'http://www.liulongbin.top:3006/api/post'
    var paramObj = {address:'南京',location:'栖霞区'}
    axios.post(url,paramObj).then(function (res){
      console.log(res.data)
    })
  })

(3)直接使用axios发起请求

axios 也提供了类似于jQuery 中 $.ajax(的函数

axios({
  method:'请求类型',
  url:'请求的url地址',
  data:{ /*post数据*/ },
  param:{ /*get参数*/ }
}).then(callback)

  <script src="lib/axios.js"></script>
</head>
<body>
  <button id="btn3">直接用axios发起get请求</button>
  <button id="btn4">直接用axios发起post请求</button>
  <script>
  //  3、直接使用axios发起请求-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,有s 不要忘记
        params :paramsData
      }).then(function (res){
        console.log(res.data)
      })
    })

    //  3、直接使用axios发起请求-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)
      })
    })
  </script>

跨域与JSONP

1、同源策略和跨域

(1)同源策略

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

例如,下表给出了相对于http://www.test.com/index.html页面的同源检测(默认端口80):

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wHVCMvLS-1669643354994)(1669602753310.png)]

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

MDN官方给定的概念:同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。

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

  • 无法读取非同源网页的Cookie、LocalStorage和IndexedDB
  • 无法接触非同源网页的DOM
  • 无法向非同源地址发送Ajax请求

(2)跨域

同源指的是两个URL的协议、域名、端口一致反之,则是跨域。

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

1)浏览器对跨域请求的拦截

允许发起请求,也可以接收响应的数据,但数据会被同源策略拦截,并不会交给ajax

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OKDWPyHa-1669643354994)(1669603532559.png)]

2)如何实现跨域数据请求

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

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

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

2、JSONP

JSONP (JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。

(1)JSONP的实现原理

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

因此,JSONP的实现原理,就是通过

<body>
  <script>
    function abc(data) {
      console.log('拿到了Data数据:')
      console.log(data)
    }
  </script>

<!--  通过script的src属性动态请求js中的代码,然后执行-->
<!--  希望服务器返回一个调用abc的函数-->
  <script src="js/getdata.js?callback=abc"></script>
</body>

(2)实现一个简单的JSONP

<body>
  <script>
    function abc(data){
      console.log('JSONP响应回来的数据')
      console.log(data)
    }
  </script>

  <script src="http://www.liulongbin.top:3006/api/jsonp?callback=abc&name=ls&age=30"></script>
</body>

(3)JSONP的缺点

由于JSONP是通过

注意:**JSONP和 Ajax之间没有任何关系,**不能把JSONP请求数据的方式叫做Ajax,因为JSONP没有用到XMLHttpRequest这个对象

(4)jQuery中的JSONP

jQuery提供的$.ajax()函数,除了可以发起真正的Ajax数据请求之外,还能够发起JSONP 数据请求

如果要使用$ .ajax ()发起JsONP请求,必须指定 datatype 为 jsonp

默认情况下,使用jQuery 发起JSONP请求,会自动携带一个callback=jQueryxxx的参数,jQueryxxx是随机生成的一个回调函数名称。

  <script src="lib/jquery.js"></script>
</head>
<body>
<script>
  $(function (){
    //发起JSONP请求
    $.ajax({
      url:'http://www.liulongbin.top:3006/api/jsonp?name=ls&age=30',
      //如果要使用$ .ajax ()发起JsONP请求,必须指定 datatype 为 jsonp
      //代表要发起jsonp请求
      dataType:'jsonp',
      success:function (res){
        console.log(res)
      }

    })
  })
</script>
</body>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tSdm14cM-1669643354995)(1669606351981.png)]

(5)自定义参数及回调函数名称

在使用jQuery 发起JSONP请求时,如果想要自定义JSONP的参数以及回调函数名称,可以通过如下两个参数来指定

// 发送到服务端的参数名称.默认值为callback,一般不修改
  jsonp: 'callback ' ,
// 自定义的回调函数名称.默认值为jQueryxxx格式
  jsonpCallback: 'abc' ,

<script>
  $(function (){
    //发起JSONP请求
    $.ajax({
      url:'http://www.liulongbin.top:3006/api/jsonp?name=ls&age=30',
      //如果要使用$ .ajax ()发起JsONP请求,必须指定 datatype 为 jsonp
      //代表要发起jsonp请求
      dataType:'jsonp',
      // 发送到服务端的参数名称.默认值为callback,一般不会修改
      jsonp: 'callback',
      // 自定义的回调函数名称.默认值为jQueryxxx格式
      jsonpCallback: 'abc',
      success:function (res){
        console.log(res)
      }
    })
  })
</script>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q3TNpw1Q-1669643354996)(1669606894955.png)]

(6)jQuery中JSONP的实现过程

jQuery 中的 SONP,也是通过

  • 发起JSONP 请求的时候,动态向

    append一个

  <script src="lib/jquery.js"></script>
</head>

<body>
  <button id="btnJSONP">发起JSONP数据请求</button>

  <script>
    $(function () {
      $('#btnJSONP').on('click', function () {
        $.ajax({
          url: 'http://www.liulongbin.top:3006/api/jsonp?address=南京&location=栖霞',
          dataType: 'jsonp',
          jsonpCallback: 'abc',
          success: function (res) {
            console.log(res)
          }
        })
      })
    })
  </script>
</body>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kpJnMZAJ-1669643354998)(1669607303105.png)]

淘宝搜索案例–完整代码🌓

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="ie=edge" />
  <title>Document</title>
  <!-- 导入页面的基本样式 -->
  <link rel="stylesheet" href="css/search.css" />
  <!-- 导入 jQuery -->
  <script src="lib/jquery.js"></script>
  <!-- 导入模板引擎 -->
  <script src="lib/template-web.js"></script>
</head>

<body>
  <div class="container">
    <!-- Logo -->
    <img src="images/taobao_logo.png" alt="" class="logo" />

    <div class="box">
      <!-- tab 栏 -->
      <div class="tabs">
        <div class="tab-active">宝贝</div>
        <div>店铺</div>
      </div>
      <!-- 搜索区域(搜索框和搜索按钮) -->
      <div class="search-box">
        <input id="ipt" type="text" class="ipt" placeholder="请输入要搜索的内容" /><button class="btnSearch">
          搜索
        </button>
      </div>
      <!-- 定义搜索建议列表 -->
      <div id="suggest-list"></div>
    </div>
  </div>

<!--  3、渲染建议列表的UI结构-->
  <!-- 定义模板结构 -->
  <script type="text/html" id="tpl-suggestList">
    {{each result}}
<!--    搜索建议项-->
<!--  $value是result中的每一项,$value[0]是每一项的第一个元素也就是建议项  -->
      <div class="suggest-item">{{$value[0]}}</div>
    {{/each}}
  </script>

  <script>
    $(function (){
      //5、缓存搜索的建议列表----1、定义全局缓存对象
      var catchObj = {}
      //实现防抖---1、定义延时器id
      var timer = null
      //实现防抖---2、定义防抖函数
      function debounceSearch(kw){
        timer = setTimeout(function (){
          getSuggestList(kw)
        },500)
      }

      // 1、为了获取到用户每次按下键盘输入的内容,需要监听输入框的keyup事件,
      $('#ipt').on('keyup',function (){
        //实现防抖---3、清空timer
        clearTimeout(timer)
        //获取用户输入内容
        var keywords = $(this).val().trim()
        //判断用户输入内容是否为空
        /*发现这里写<的时候不用清空,会自动清空建议列表,
        也就是<0的时候会调用 getSuggestList(keywords),从而调用renderSuggestList(res),
        里面有return $('#suggest-list').empty().hide(),所以会自动清空*/
        if (keywords.length <= 0){
          //4、如果关键词为空,则清空后隐藏搜索建议列表
          return $('#suggest-list').empty().hide()
        }

        //5、缓存搜索的建议列表----优先获取缓存中的搜索列表
        //先判断缓存中有数据没,有的话,将数据return出去并渲染ui结构
        if (catchObj[keywords]){
          return renderSuggestList(catchObj[keywords])
        }
        //   console.log(keywords)
      //  2、用户输入内容不为空时,获取搜索列表
      //  将获取搜索建议列表的代码,封装到getSuggestList函数中,
      //   getSuggestList(keywords)
        //实现防抖---4、调用防抖函数
        debounceSearch(keywords)
      })

    // 2、 封装getSuggestList函数 获取搜索建议列表
      function getSuggestList(kw){
        $.ajax({
          url:'https://suggest.taobao.com/sug?q=' + kw,
          dataType:'jsonp',
          success:function (res){
            console.log(res)
            renderSuggestList(res)
            // $('#suggest-list').html(template('tpl-suggestList',res)).css('display','block')
          }
        })
      }

    //  3、定义渲染模板结构的函数
      function renderSuggestList(res){
        if (res.result.length<=0){
          return $('#suggest-list').empty().hide()
        }
        var htmlStr = template('tpl-suggestList',res)
        $('#suggest-list').html(htmlStr).show()

        //5、缓存搜索的建议列表----2、将搜索结果保存到缓存对象中(键值对形式)
      //  获取到用户输入的内容,当做键
        var k = $('#ipt').val().trim()
      //  将数据作为值,进行缓存
        catchObj[k] = res
      }

    })
  </script>
</body>
</html>

3、防抖和节流

(1)输入框的防抖(典型👊)

防抖策略(debounce)是当事件被触发后,延迟n秒后再执行回调,如果在这n秒内事件又被触发,则重新计时。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6XXhakMh-1669643354998)(1669618524547.png)]

**好处:**频繁触发某个事件时,可以保证这个事件最终只被执行一次,能减少不必要回调的执行

1)防抖的引用场景

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

2)实现输入框的防抖
//实现防抖---1、定义延时器id
var timer = null
//实现防抖---2、定义防抖函数
function debounceSearch(kw){
  timer = setTimeout(function (){
    getSuggestList(kw)
  },500)
}
// 1、为了获取到用户每次按下键盘输入的内容,需要监听输入框的keyup事件,
      $('#ipt').on('keyup',function (){
        //实现防抖---3、清空timer
        clearTimeout(timer)
        //获取用户输入内容
        var keywords = $(this).val().trim()
        //判断用户输入内容是否为空
        if (keywords.length <= 0){
          //4、如果关键词为空,则清空后隐藏搜索建议列表
          return $('#suggest-list').empty().hide()
        }
        //实现防抖---4、调用防抖函数
        debounceSearch(keywords)
      })

(2)节流

节流策略(throttle),顾名思义,可以减少—段时间内事件的触发频率。

区别就是,防抖打断要重新计时,节流按下了不会停打断不了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fHgtVfu7-1669643354999)(1669623538340.png)]

1)节流的应用场景
  • 鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次
  • 懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费CPU资源
2)节流阀

高铁卫生间是否被占用,由红绿灯控制,红灯表示被占用,绿灯表示可使用。

假设每个人上卫生间都需要花费5分钟,则五分钟之内,被占用的卫生间无法被其他人使用。上一个人使用完毕后,需要将红灯重置为绿灯,表示下一个人可以使用卫生间。
下一个人在上卫生间之前,需要先判断控制灯是否为绿色,来知晓能否上卫生间.

  • 节流阀为空,表示可以执行下次操作;不为空,表示不能执行下次操作。
  • 当前操作执行完,必须将节流阀重置为空,表示可以执行下次操作了。
  • 每次执行操作前,必须先判断节流阀是否为空
    <script src="lib/jquery.js"></script>
    <style>
        html,body{
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
        #angel{
            position: absolute;
        }
    </style>
</head>
<body>
<img src="angel.gif" alt="" id="angel">

<script>
    $(function (){
    //    1、获取到图片
        var angel = $('#angel')
    //    节流阀优化---1、定义一个timer节流阀
        var timer = null
    //    2、绑定mousemove事件
        $(document).on('mousemove',function (e){
            // console.log(e.pageX,e.pageY)//e.pageX,e.pageY获取到鼠标的横纵坐标
            //节流阀优化---3、判断节流阀是否为空,如果不为空,则证明上次执行间隔不足16毫秒,就return结束代码执行
            if (timer) {return}
            //节流阀优化---2、定义延时器
            timer = setTimeout(function (){
                // 3、设置图片的位置   把鼠标的位置赋值给图片
                $(angel).css('top',e.pageY + 'px').css('left',e.pageX + 'px')
                console.log('ok')
                //节流阀优化---2、当设置了鼠标跟随效果后,清空timer节流阀,方便下次开启延时器
                timer = null
            },16)
        })
    })
</script>
</body>

(3)防抖和节流的区别

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

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

HTTP协议

1、HTTP协议简介

(1)什么是通信

通信,就是信息的传递和交换。

通信三要素:
通信的主体,通信的内容,通信的方式

  • 现实中的通信

案例:张三要把自己考上传智专修学院的好消息写信告诉自己的好朋友李四

通信的主体是张三和李四;通信的内容是考上传智专修学院;通信的方式是写信;

  • 互联网中的通信:

案例:服务器传智专修学院的简介通过响应的方式发送给客户端浏览器

(2)什么是通信协议

通信协议(Communication Protocol))是指通信的双方完成通信所必须遵守的规则和约定。

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

  • 现实生活中的通信协议:

张三与李四采用写信的方式进行通信,在填写信封时,写信的双方需要遵守固定的规则。信封的填写规则就是一种通信协议

  • 互联网中的通信协议

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

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

(3)HTTP协议

1)什么是HTTP协议

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

例如:
客户端要以HTTP协议要求的格式把数据提交到服务器
服务器要以HITP协议要求的格式把内容响应给客户端

2)HTTP协议的交互模型

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PuGUyZxA-1669643355000)(1669430538587.png)]

2、HTTP请求消息

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

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

HTTP请求消息的组成部分

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k1fXQ10t-1669643355000)(1669628309497.png)]

1)请求行

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TICpqIqC-1669643355001)(1669626325183.png)]

get请求行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l5hhQzSM-1669643355001)(1669626675259.png)]

post请求行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7KglOJMM-1669643355001)(1669627154358.png)]

  <script src="lib/jquery.js"></script>
</head>

<body>
  <button id="btnGET">GET请求</button>
  <button id="btnPOST">POST请求</button>

  <script>
    $(function () {

      // 发起 GET 请求
      $('#btnGET').on('click', function () {
        $.ajax({
          method: 'GET',
          url: 'http://www.liulongbin.top:3006/api/get',
          data: {
            name: 'zs',
            age: 20
          },
          success: function (res) {
            console.log(res)
          }
        })
      })

      // 发起 POST 请求
      $('#btnPOST').on('click', function () {
        $.ajax({
          method: 'POST',
          url: 'http://www.liulongbin.top:3006/api/post',
          data: {
            name: 'zs',
            age: 20
          },
          success: function (res) {
            console.log(res)
          }
        })
      })
    })
  </script>
</body>

2)请求头部

请求头部用来描述客户端的基本信息,从而把客户端相关的信息告知服务器。

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sRKz7pEi-1669643355002)(1669627414885.png)]

常见的请求头字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PWA8MuSH-1669643355003)(1669627532820.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u3acPuMP-1669643355003)(1669627745034.png)]

3)空行

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1rRVKGCt-1669643355004)(1669627982250.png)]

4)请求体

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uGGkIlOZ-1669643355004)(1669627984839.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6DFhKhkV-1669643355004)(1669628151334.png)]

3、HTTP响应消息

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

HTTP响应消息的组成部分

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9P5VjmFm-1669643355005)(1669628482603.png)]

1)状态行

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HId4OhTR-1669643355005)(1669628588592.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wLYSecU5-1669643355006)(1669628782760.png)]

2)响应头部

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

常见字段官方文档:

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jy1xsLeV-1669643355007)(1669629039806.png)]

3)空行

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

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

4)响应体

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b2xEvZM0-1669643355007)(1669629156309.png)]

4、HTTP请求方法

HTTP请求方法,属于HTTP协议中的一部分,请求方法的作用是:用来表明要对服务器上的资源执行的操作。最常用的请求方法是GET和POST.,还有put、delete

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aSL87mqQ-1669643355008)(1669629350613.png)]

5、HTTP响应状态码

HTTP响应状态码(HTTP Status Code),也属于HTTP协议的一部分,用来标识响应的状态。

响应状态码会随着响应消息一起被发送至客户端浏览器,浏览器根据服务器返回的响应状态码,就能知道这次HTIP请求的结果是成功还是失败了。

(1)HTTP响应状态码的组成及分类

HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字用来对状态码进行详细的划分。

HTTP响应状态码共分为5种类型

分类分类描述
1****信息,服务器收到清求,需要请求者继续执行操作(实际开发中很少遇到1类型的状态码)
2****成功,**操作被成功接收并处理
3****重定向,**需要进一步的操作以完成请求
4****客户端错误,**请求包含语法错误或无法完成请求
5****服务器错误。**服务器在处理请求的过程中发生了错误

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

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

状态码状态码英文名称中文描述
200OK**请求成功,**一般用与GET与POST请求
201Created**已创建。**成功清求并创建了新的资源,通常用于POST 或PUT 请求

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

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

状态码状态码英文名称中文描述
301Moved permanently**永久移动。**请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302Found**临时移动。**与301类似。但资源只是临时被移动。客户端应继续使用原有URI
304Not Modified**末修改。**所请求的资源未修改,服务器返回此状态码时,不会返回任何资源(响应消息中不包含响应体)。客户端通常会缓存访问过的资源。

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

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

状态码状态码英文名称中文描述
400Bad Request1、语义有误,当前请求无法被服务器理解。除非进行修改,否则客户端不应该重复提交这个请求。2、请求参数有误。
401Unauthorized当前请求需要用户验证。
403Forbidden服务器已经理解请求,但是拒绝执行它。
404Not Found服务器无法根据客户端的请求找到资源(网页).
408Request Timeout请求超时。服务器等待客户端发送的请求时间过长,超时。

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

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

状态码状态码英文名称中文描述
500lnternal Server Error服务器内部错误。无法完成请求。
501Not Implemented服务器不支持该请求方法,无法完成请求。只有GET 和HEAD请求方法是要求每个服务器必须支持的,其它请求方法在不支持的服务器上会返回501
503Service Unavailable由于超载或系统维护,服务器暂时的无法处理客户端的请求。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值