前端与移动开发----Ajax编程----JSON字符串,XHR2.0新特性,节流函数

Ajax编程

回顾

  1. Ajax底层原生使用的XMLHttpRequest构造函数, 它是window身上的一个属性(浏览器的一个接口)

  2. GET是在url后面?拼接参数传递给后台

  3. POST方式是在body体里发送给后台

  4. 如果发送文件, 需要保证发送内容类型不是字符串 而是multipart/form-data

  5. 收集表单里的值

    serialize

    • 不能收集带文件的
    • 被禁用的标签不能被收集
    • 收集时, key是name属性的值, value是表单的值

8. JSON

8.0 JSON字符串写法

后台数据的载体(表现形式)可以是JSON字符串

轻量级的数据交换格式

JSON字符串和JS数据转换

// 为什么要有JSON出现呢?
// 因为JS的数组/对象 转成字符串, 没办法使用了
var obj = {
    
    name: "小明"};
console.log(obj.toString()); // 字符串类型 [object Object]

// 所以引入JSON数据格式字符串使用
var obj = {
    
    name: "小明"};
console.log(JSON.stringify(obj)); // 字符串类型 {"name":"小明"}

// 后台返回数组/对象数据时, 传递的数据是JSON格式字符串

8.1 JSON文件介绍

  • 不允许写注释
  • 不能有函数
  • 属性名, 字符串类型的值,必须加引号
  • 一个完整的JSON字符串,前后的括号必须对应

不会出现undefined、不会有function、不会有注释

{
    
    
    "name": "hello",
    "age": 18,
    "marry": false
}

9. XHR2.0新特性

XHR2.0 – 简介

XMLHttpRequest是一个浏览器提供的API。HTML 5的概念形成后,W3C在2008年2月,XMLHttpRequest的新版本,提出了很多有用的新功能

  • XHR1.0
    • 只支持文本数据的传输,无法上传文件
    • 传送和接收数据时,没有进度信息
    • 属性和方法
      • readyState
      • responseText
      • onreadystatechange
      • open
      • send
      • status
      • setRequestHeader
  • XHR2.0
    • 可设置 HTTP 请求的时限
    • 可使用 FormData 对象管理带文件的表单数据, 可以上传文件
    • 可以获得数据传输的进度信息
    • 属性和方法
      • response
      • responseType
      • onload等一系列新的事件(onprogress、onloadstart、onloadend)
      • timeout - 超时时间(设置几秒钟超时)
      • ontimeout - 超时事件
      • upload - 上传动作

9.0 设置HTTP请求时限

  • timeout – 超时毫秒
  • ontimeout – 请求超时事件
var btn = document.getElementById("btn");
btn.onclick = function () {
    
    
    var ajax = new XMLHttpRequest();
    ajax.onreadystatechange = function () {
    
    
        if (ajax.readystate == 4 && ajax.status == 200) {
    
    
            console.log(ajax.responseText);
        }
    }
    ajax.open("GET", "URL/api/st");
    ajax.send();

    // 超时时间, 单位是毫秒
    ajax.timeout = 2000;
    // 超时事件
    ajax.ontimeout = function () {
    
    
        alert('请求超时,请刷新重试');
    }
    // 超时后自动关闭本次ajax请求
}

9.1 使用onload新事件

  • xhr.onload
    • 请求响应成功之后触发
    • 而且是在 xhr.readyState===4的时候触发
    • 可以用它代替onreadystatechange事件
// XHR2.0 新出onload方法
var btn = document.getElementById("btn");
btn.onclick = function () {
    
    
    var ajax = new XMLHttpRequest();
    // 1. 状态为4(收集完后台返回结果) - http状态200
    // 触发onload(替代onreadystatechange和判断)
    ajax.onload = function () {
    
    
        console.log(JSON.parse(ajax.responseText));
        console.log(ajax.response);
    }

    ajax.open("GET", "URL/api/getbooks");
    ajax.send();
}

9.2 FormData使用

web前端 向 后端 发送数据的内容载体

具体选择GET/POST哪一种, POST方式内容类型, 要看后端要什么, 前端就给什么… 匹配上即可

// 好处: 可以一键收集表单的信息
var theBtn = document.getElementById("btn");
var theForm = document.getElementById("myForm");
theBtn.onclick = function(ev){
    
    
    ev.preventDefault();
    var formData = new FormData(theForm); // 把form穿进去, 参数名和值会自动收集起来

    // 还可以自己往formData上拼接
    formData.append("a", 100);
    // 更多的方法可以看这里(一般用不上)https://developer.mozilla.org/zh-CN/docs/Web/API/FormData

    // 打印查看formData里的东西
    formData.forEach(function(value, key){
    
    
        console.log(value, key);
    })

    var ajax = new XMLHttpRequest();
    ajax.onload = function () {
    
    
        console.log(JSON.parse(ajax.responseText));
        console.log(ajax.response);
    }

    ajax.open("POST", "URL/api/upload/avatar"); // 表单提交一般用POST方式
    ajax.send(formData);

}

// 总结:
// jQ的方法 $("form标签").serialize() 原地返回结果 key=value&key=value的字符串(注意key指的每个表单标签name属性的值)
// 原生的 new FormData(原生form标签)  原地返回结果 是一个FormData对象(带有分割符的键值对格式)

使用注意

  • 实例化 FormData对象,传入表单的DOM对象。得到的结果就会包含表单的各项数据了
  • FormData也是根据表单各项的name属性获取值的
  • 可以收集文件类型的信息,serialize只能收集非文件的name和值
  • 对于下拉框来说,name设置给select标签,value设置给option标签;
  • ajax提交,直接提交fd对象即可,不需要把它转成查询字符形式。(xhr.send(fd)
  • 不用自己设置请求头;XHR对象会自动设置这个Content-Type请求头

POST 两种内容区别

  • application/x-www-form-urlencode (默认)

在这里插入图片描述

  • form/data的下面
    在这里插入图片描述

在这里插入图片描述

点击view source 可以看到参数真正的样子

在这里插入图片描述

9.3 上传文件 - 带进度条(原生)

实现过程:

  1. 实现ajax提交FormData数据
  2. 注册xhr.upload.onprogress事件,监测进度

注意,上传进度使用xhr.upload.onprogress事件;下载进度使用xhr.onprogress事件;

<!-- 1. 文件选择框 -->
<input type="file" id="file1" />
<!-- 2. 上传文件的按钮 -->
<button id="btnUpload">上传文件</button>

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

<br />
<!-- 3. img 标签,来显示上传成功以后的图片 -->
<img src="" alt="" id="img" width="800" />

<script>
    // 1. 上传按钮
    var btnUpload = document.querySelector('#btnUpload')
    // 2. 上传按钮 - 点击事件
    btnUpload.addEventListener('click', function () {
      // 3. 用户选择的文件列表
      var files = document.querySelector('#file1').files
      if (files.length <= 0) {
        return alert('请选择要上传的文件!')
      }

      // 4. 准备FormData对象 - 装载表单数据
      var fd = new FormData()
      fd.append('avatar', files[0])

      // 5. Ajax - 监听文件上传的进度 (upload上传, onprogress进度, 只要上传的进度改变就触发此事件)
      var xhr = new XMLHttpRequest()

      xhr.upload.onprogress = function (e) {
        if (e.lengthComputable) { // 是否具有可以计算的长度

          // 6. 计算出上传的进度 (e.loaded已上传字节数, e.total共要上传的字节数)
          var procentComplete = Math.ceil((e.loaded / e.total) * 100)
          console.log(procentComplete)
          // 动态设置进度条
          $('#percent').attr('style', 'width: ' + procentComplete + '%;').html(procentComplete + '%')
        }
      }

      xhr.open('POST', 'http://123.57.109.30:3006/api/upload/avatar')
      xhr.send(fd)

      xhr.onload = function () {
          var data = JSON.parse(xhr.responseText)
          if (data.status === 200) { // 后台返回的代码逻辑的状态码(而非http状态码)
            // 上传成功
            $('#percent').removeClass().addClass('progress-bar progress-bar-success');
            document.querySelector('#img').src = data.url
          } else {
            // 上传失败
            console.log('图片上传失败!' + data.message)
          }
      }
    })

9.4 上传文件 - 带加载器(jQ)

$(function () {
    
    
    // 1. 监听到整个文档 - 有Ajax请求被发起了
    $(document).ajaxStart(function () {
    
    
        $('#loading').show()
    })

    // 2. 监听到整个文档 - 有Ajax完成的事件
    $(document).ajaxStop(function () {
    
    
        $('#loading').hide()
    })

    // 3. 点击发起 Ajax
    $('#btnUpload').on('click', function () {
    
    
        var files = $('#file1')[0].files
        if (files.length <= 0) {
    
    
            return alert('请选择文件后再上传!')
        }

        // 4. 准备表单容器
        var fd = new FormData()
        fd.append('avatar', files[0])

        // 发起 jQuery 的 Ajax 请求,上传文件
        $.ajax({
    
    
            method: 'POST',
            url: 'http://123.57.109.30:3006/api/upload/avatar',
            data: fd,
            processData: false,
            contentType: false,
            success: function (res) {
    
    
                console.log(res)
            }
        })
    })
})

10. 案例 - 新闻列表

  • 案例图示如下
    • 调用后台接口获取新闻列表数据
    • 拉到底部加载更多, 如果没有更多数据(后台会返回是否还有更多), 给出提示(关闭下拉加载更多的方法)

在这里插入图片描述

10.0 案例 - 新闻列表 - 获取数据

// 2. 格式化日期
Date.formatTime = function (date) {
    
    
    function padZero(n) {
    
    
        if (n < 10) {
    
    
            return '0' + n
        } else {
    
    
            return n
        }
    }
    // 把字符串格式的日期转换为日期对象
    var d = new Date(date)
    var year = padZero(d.getFullYear())
    var month = padZero(d.getMonth() + 1)
    var day = padZero(d.getDate())
    var hour = padZero(d.getHours())
    var minute = padZero(d.getMinutes())
    var second = padZero(d.getSeconds())
    return year + '-' + month + '-' + day + ' ' + hour + ':' + minute + ':' + second
}

// 1. Ajax请求数据 - 铺设第一页数据
var nowPage = 1;
function loadNewsList() {
    
    
    $.ajax({
    
    
        url: "http://123.57.109.30:3006/api/news",
        data: {
    
     page: nowPage },
        type: "GET",
        success(res) {
    
    
            var arr = res.data;
            arr.forEach(function (obj, index) {
    
    
                var tagsArr = obj.tags.split(",");
                $("#news-list").append(`<div class="news-item">
<img class="thumb" src="http://123.57.109.30:3006${
      
      obj.img}" alt="">
<div class="right-box">
<h1 class="title">${
      
      obj.title}</h1>
<div class="tags">
<span>${
      
      tagsArr[0]}</span>
<span>${
      
      tagsArr[1]}</span>
<span>${
      
      tagsArr[2]}</span>
</div>
<div class="footer">
<div>
<span>${
      
      obj.source}</span>&nbsp;&nbsp;
<span>${
      
      Date.formatTime(obj.time)}</span>
</div>
<span>评论数:${
      
      obj.cmtcount}</span>
</div>
</div>
</div>`)
            })
        }
    })
}
loadNewsList();

10.1 案例 - 新闻列表 - 下拉加载更多

// 3. 监测网页是否滚动到底部
$(document).on("scroll", function(){
    
    
    if ($(document).scrollTop() >= document.documentElement.scrollHeight - document.documentElement.clientHeight) {
    
    
        nowPage++;
        loadNewsList();
    }
})

10.2 案例 - 新闻列表 - 节流阀

// 3. 监测网页是否滚动到底部
var timer = null; // 保存定时器
$(document).on("scroll", function () {
    
    
    if (timer) return; // 如果有定时器再触发函数就回去不继续执行下面的

    timer = setTimeout(function () {
    
    
        if ($(document).scrollTop() >= document.documentElement.scrollHeight - document.documentElement.clientHeight) {
    
    
            nowPage++;
            loadNewsList();
        }

        timer = null;
    }, 300);
})

10.3 节流函数

// 3. 监测网页是否滚动到底部
$(document).on("scroll", throttle(function () {
    
    
    if ($(document).scrollTop() >= document.documentElement.scrollHeight - document.documentElement.clientHeight) {
    
    
        nowPage++;
        loadNewsList();
    }
}, 300))

// 4. 定义节流函数
function throttle(fn, theTime) {
    
    
    return function () {
    
    
        if (fn.timer) return;
        fn.timer = setTimeout(() => {
    
    
            fn.call(this, ...arguments);
            fn.timer = null;
        }, theTime);
    }
}

如有不足,请多指教,
未完待续,持续更新!
大家一起进步!

猜你喜欢

转载自blog.csdn.net/qq_40440961/article/details/111596553