Ajax编程
回顾
- Ajax底层原生使用的XMLHttpRequest构造函数, 它是window身上的一个属性(浏览器的一个接口)
- GET是在url后面?拼接参数传递给后台
- POST方式是在body体里发送给后台
- 如果发送文件, 需要保证发送内容类型不是字符串 而是multipart/form-data
- 收集表单里的值
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 上传文件 - 带进度条(原生)
实现过程:
- 实现ajax提交FormData数据
- 注册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>
<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);
}
}
如有不足,请多指教,
未完待续,持续更新!
大家一起进步!