什么是网络?
用网线/无线信号 - 链接在一起的各种电脑形成网络
什么是资源?
数据, 字符串, 文件, 视频, 音频等等, 存储在电脑上的。
服务器和客户端
客户端负责浏览和使用各种资源的设备(个人电脑/个人手机等等)
服务器负责提供各种数据资源
URL
客户端想要去请求资源, 需要知道资源在哪里. 所以URL是一串地址, 标记资源在哪里. (叫统一资源定位符)
IP
URL中开头部分, 用于标识网络中哪台计算机的地址
域名
ip是一串以.分割的4段数字, 很难记住, 所以我们有了域名(一串.分割的英文字符)
DNS服务
负责记录域名和IP的对应关系, 用于把域名翻译成IP地址的功能, 负责在网络里寻找目标电脑的IP
请求响应过程
客户端 -> 请求 -> 服务器
客户端 <- 响应 <- 服务器
请求的分类
Ajax请求方式
在JS代码中, 编写一段代码就可以在html网页中嵌入一个请求的方式, 返回的数据到JS代码的地方
必备能力
学会从Network里分析网络请求(跟css / console打印一样)
请求方式
使用Ajax
$.ajax({
type: “”, // 请求方式 - 默认不写是GET(大小写都可以)
url: “”, // 请求的后端地址
data: {}, // 里面可以向后台传递数据
success: function(res){} // 固定是一个函数题(用于接受后台返回的结果
})
后端接口
就是使用的URL: 只不过这个url返回的不是网页, 而是一串字符串数据
接口调试工具
之前用的是JQ封装的Ajax功能, 这节课我们来看看内部实现的原理
// 1. 实例化ajax对象
var ajaxObj = new XMLHttpRequest();
// 2. 注册 onreadystatechange 事件
/*
下面事件的触发时机, ajax对象的readyState状态改变时触发
0 - ajax对象被创建
1 - open一定被调用
2 - send一定被调用
3 - 正在接收服务器数据
4 - 服务器数据接收完毕
当0变到1, 触发一次onreadystatechange事件, 当1到2, 当2到3, 当3到4都会触发onreadystatechange事件执行
*/
// ajax(XMLHttpRequest) 让浏览器发起一次 -> http网络请求
ajaxObj.onreadystatechange = function () {
// 4(数据接收完毕)(JS代码层面), status代表http网络请求成功(200)
if (ajaxObj.readyState === 4 && ajaxObj.status === 200) {
// responseText 取出请求回来的字符串数据
var res = JSON.parse(ajaxObj.responseText);
console.log(res);
}
}
// 3. 调用open方法,设置请求方式及请求的url地址
ajaxObj.open('GET', 'URL');
// 4. 最后,调用send方法,发送这次ajax请求
ajaxObj.send();
readyState属性和onreadystatechange事件
Ajax从创建xhr对象开始,一直到完全接收服务器返回的结果为止;我们可以把整个请求响应过程划分为几个阶段。
请求阶段 - 异步等待阶段 - 响应阶段
在url后面拼接的请求参数,就是 “xxx=sss&yyy=mmm&zzz=bbb” 这种格式的字符串,叫做查询字符串
// 1. id为3的书籍信息
// 1.1 创建Ajax对象 - 绑定状态改变事件(准备接受返回的数据)
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function () {
if (ajax.readyState === 4 && ajax.status === 200) {
var res = JSON.parse(ajax.responseText);
console.log(res);
}
}
// 1.2 设置请求方式, 请求的url以及参数
ajax.open('GET', 'URL?id=3');
// 1.3 发送请求
ajax.send();
// 2. id为1且bookname是西游记
// 2.1 再创建一个Ajax对象
var ajaxObj = new XMLHttpRequest();
// 2.2 绑定事件
ajaxObj.onreadystatechange = function () {
if (ajaxObj.readyState === 4 && ajaxObj.status === 200) {
var res = JSON.parse(ajaxObj.responseText);
console.log(res);
}
}
// 2.3 设置请求方式 - 请求url - 参数拼接
ajaxObj.open('GET', 'URL?bookname=西游记&id=1');
// 2.4 发送请求
ajaxObj.send();
// 编码: 计算机保存/传输一切都是以0和1位基本的, 给我们展示的时候, 就得转换编程成另一种形式
// url编码: 把url地址中的非英文字符转成另外一种编码形式, 确保后台准确解析我通过url的参数
// 方法1: 快速编码和解码
console.log(encodeURI('西游记&')); // %E8%A5%BF%E6%B8%B8%E8%AE%B0&
console.log(decodeURI('%E8%A5%BF%E6%B8%B8%E8%AE%B0&'));// 西游记&
// 方法2: 范围更广的 编码 和 解码
console.log(encodeURIComponent('西游记&')); // %E8%A5%BF%E6%B8%B8%E8%AE%B0%26
console.log(decodeURIComponent('%E8%A5%BF%E6%B8%B8%E8%AE%B0%26')); // 西游记&
// 方法2, 可以编码的字符比较多
// 可以对 ;/?:@&=+$,# 进行编码
// 两个函数都不会对 - _ . ! ~ * ' ( ) 进行编码
// 使用场景:
// 问题:
// 我们都知道url传递的格式是key=value&key=value
// 但是当我的值里也出来了&, 就破坏了解析字符串的规则, 后台解析失败
// 1.1 创建 Ajax对象
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function () {
if (ajax.readyState === 4 && ajax.status === 200) {
var res = JSON.parse(ajax.responseText);
console.log(res);
}
}
// 1.2 设置请求方式, 请求的url以及参数
ajax.open('GET', 'URL?a=6&10');
// 1.3 发送请求
ajax.send();
// 解决: 进行url编码
var str = encodeURIComponent("6&10");
console.log(str);
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function () {
if (ajax.readyState === 4 && ajax.status === 200) {
var res = JSON.parse(ajax.responseText);
console.log(res);
}
}
// 1.2 设置请求方式, 请求的url以及参数
ajax.open('GET', `URL?a=${
str}`);
// 1.3 发送请求
ajax.send();
和GET请求的两个区别
document.getElementById("createBtn").onclick = function () {
// 1.1 创建Ajax对象 - 监测事件
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
var res = JSON.parse(this.responseText);
console.log(res);
}
}
// 1.2 设置请求方式 - 请求的url
ajax.open('POST', 'URL');
// // 必须在open和send之间加一个请求头,这个请求头写法固定。记不住可以复制
// 1.3 设置请求头 - 告诉后端, 我给你发送的内容类型
// 意思是以xxx=yyy&zzz=ttt的格式传递参数给后台, 后台从Content-type发现值是下面这个就按照对应的规则来解析这个字符串, 提取参数名和值了
ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// 1.4 发送请求并且携带参数, 格式固定
// POST方式提交的数据,仍然是查询字符串格式,只不过位置改变了
ajax.send('bookname=红与黑&author=司汤达&publisher=法国出版社&appkey=b7fc2560-5632-4da5-b625-58cff58c6b31');
}
练习1: 编写原生Ajax代码 - 请查询公共数据(无需带appkey参数), 中id为2的数据信息 (这是要哪数据吧? 用那种请求方式呢?)
let ajaxObj = new XMLHttpRequest();
ajaxObj.onreadystatechange = function(){
if (ajaxObj.readyState == 4) {
if (ajaxObj.status == 200) {
console.log(ajaxObj.responseText);
}
}
}
// 总结: 多个参数要在?后面 以参数名=值&参数名=值
ajaxObj.open("GET", "URL?id=2");
ajaxObj.send();
练习2: 编写原生Ajax代码 - 请向自己的表中(带appkey和自己的值), 向后台随便增加一条书籍信息, 然后调用查询自己书籍信息的接口, 查看是否添加成功 - (这是要发送数据吧? 应该用什么请求方式呢?)
// 1. 实例化ajax对象
let ajaxObj = new XMLHttpRequest();
// 2. 绑定事件
ajaxObj.onreadystatechange = function(){
// 5. 接受返回的结果
if (ajaxObj.readyState == 4) {
if (ajaxObj.status == 200) {
console.log(ajaxObj.responseText);
}
}
}
// 3. 设置参数
ajaxObj.open("POST", "URL");
// (新) - 设置内容的类型
ajaxObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// 4. 发送请求
// (新)-post的参数要写在send()里面
ajaxObj.send("bookname=我是vscode插件的书籍&author=vscode&publisher=121&appkey=b7fc2560-5632-4da5-b625-58cff58c6b31");
整体
来模拟下JQ的ajax的函数内代码的执行过程
// function $(){};
// $.ajax = function(){};
// $.ajax();
// 封装函数的过程步骤:
// 1. 定义函数壳子(名字)
// 2. 调用函数, 传入一套例子(目标)
// 3. 编写(粘贴+修改)函数里的代码
// 想好哪些变量以后会变 (这次传a, 下次传b, 那么这个变量就必须在形参上)
function myAjax(obj) {
// 解构赋值提取外面参数的值
let {
type, url, data, success } = obj;
// 原生Ajax
let ajaxObj = new XMLHttpRequest();
ajaxObj.onreadystatechange = function () {
if (ajaxObj.readyState == 4) {
if (ajaxObj.status == 200) {
success(JSON.parse(ajaxObj.responseText)); // 回调外面传入的success对应的函数执行, 把值传出去
}
}
}
ajaxObj.open(type, url);
ajaxObj.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// 把对象转成字符串
// 不能用JSON.stringify, 因为字符串的格式不对, 我们要的是key=value&key=value的字符串
var arr = []; // 因为对象里有多对key=value, 所以我想要把对象没对key-value转成字符串, 多对都转在一个数据结构里(采用数组来装载)
for (var key in data) {
arr.push(`${
key}=${
data[key]}`);
}
var argStr = arr.join("&"); // join就是用()里的符号, 把数组里的每个值链接起来形成一个大字符串返回
ajaxObj.send(argStr);
}
myAjax({
type: "POST",
url: "http://123.57.109.30:3006/api/addbook",
data: {
bookname: "我是vscode插件的书籍",
author: "vscode",
publisher: "哈哈",
appkey: "b7fc2560-5632-4da5-b625-58cff58c6b31"
},
success: function (res) {
console.log(res);
}
})"
},
success: function (res) {
console.log(res);
}
})
回忆下$.ajax里传入的配置对象, 有哪些key属性和功能
封装思路
使用自己封装的Ajax方法
function $() {
};
$.ajax = function (obj) {
// 1. 默认值确保
obj.type = obj.type || "GET"; // 防止外面没传type值, 给予默认值"GET"
obj.type = obj.type.toUpperCase(); // 防止外面传的小写, 导致下面比较不相等
// 模拟JQ的ajax实现过程 - 内部使用的就是原生JS的XMLHTTPRequest
// 2. 新建Ajax对象 - 绑定事件
var ajax = new XMLHttpRequest();
ajax.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
obj.success(JSON.parse(this.responseText)) // 请求成功回调外面success函数执行, 把值传出去
}
}
// 3. 把data对象里的参数转换成这个格式 key=value&key=value
var arr = [];
for (var prop in obj.data) {
arr.push(`${
prop}=${
obj.data[prop]}`);
}
var argStr = arr.join("&"); // 拼接字符串参数
// 4. 判断是不是GET方式, 并且是否有参数, 都符合在拼接url后面?传参
if (obj.type == "GET") {
obj.url += "?" + argStr; // 注意这里必须是+=哦
}
// 5. 设置Ajax请求方式和url
ajax.open(obj.type, obj.url);
// 6. 判断是POST, 得设置请求头内容类型
obj.type.toUpperCase() == "POST" && ajax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 判断type是POST方式, 则必须执行设置请求头的内容类型
// 7. 发起Ajax请求
ajax.send(obj.type == "POST" ? argStr : '');
}
// 点击查询
document.getElementById("btn").onclick = function () {
$.ajax({
url: 'http://123.57.109.30:3006/api/getbooks',
data: {
appkey: "b7fc2560-5632-4da5-b625-58cff58c6b31"
},
success: function (res) {
console.log(res);
}
})
}
// 点击新增
document.getElementById("createBtn").onclick = function(){
$.ajax({
type: "post",
url: 'http://123.57.109.30:3006/api/addbook',
data: {
bookname: "红黑树",
author: "算法杨",
publisher: "数学出版社",
appkey: "b7fc2560-5632-4da5-b625-58cff58c6b31"
},
success: function (res) {
console.log(res);
}
})
}
以前没有Ajax的时候, 都是用表单向后台提交数据
点击 类型的按钮或者在form标签里的button,让表单自行提交到 action 指定的url位置。这就是表单的同步提交。
同步提交的缺点:
from标签的action、method、enctype、target只有在表单同步提交的时候才有用
使用一下form标签的提交方式
<h2>表单提交 - get方式h2>
<form action="URL" target="_blank">
<input type="text" name="appkey" placeholder="用户appkey">
<input type="submit" value="点击获取书籍信息">
form>
<h2>表单提交 - post方式(字符串内容)h2>
<form action="URL" method="POST" target="_blank">
<input type="text" name="bookname" placeholder="书名">
<input type="text" name="author" placeholder="作者">
<input type="text" name="publisher" placeholder="出版社">
<input type="text" name="appkey" placeholder="用户appkey">
<input type="submit" value="新增一本书">
form>
<h2>表单提交 - post方式(带文件)h2>
<form action="URL" method="POST" enctype="multipart/form-data" target="_blank">
<span>选择要上传的文件span>
<input type="file" name="img">
<input type="text" name="username" placeholder="用户名">
<input type="submit" value="传文件和参数到后台">
form>
异步提交
使用JS的手段,实现表单数据的提交。
使用方法
jQuery中提供的serializeArray和serialize方法
name属性
;这两个方法是根据表单各项的name属性获取值的// 不用form默认提交, 换成Ajax提交
// (1): form标签 - submit提交事件
// (2): 按钮(button/input) - click点击事件(触发的提交行为) - 阻止点击的默认行为(就会阻止提交行为)
// 1. GET传参 - 表单
$("#formOne input[type=submit]").on("click", function (ev) {
ev.preventDefault();
$.ajax({
type: "GET",
url: "URL",
data: {
appkey: $("#appk").val()
},
success(res) {
console.log(res);
}
})
})
// 2. POST传参 - 表单 - 不带文件
$("#formTwo input[type=submit]").on("click", function (ev) {
ev.preventDefault();
var s = $("#formTwo").serializeArray(); // 数组里套对象格式
var s2 = $("#formTwo").serialize(); // 这个是字符串key=value&key=value格式
$.ajax({
type: "POST",
url: "URL",
data: s2,
success(res) {
console.log(res);
}
})
})
// 3. POST传参 - 表单 - 带文件
$("#formThree input[type=submit]").on("click", function (ev) {
ev.preventDefault();
var files = $('#theFile')[0].files; // 获取到文件类型对象
if (files.length <= 0) {
// 判断文件是否存在
return alert('请选择文件后再上传!')
}
var fd = new FormData() // 表单数据 - 如果有文件必须用这个数据格式来传递数据
fd.append('avatar123', files[0]);
fd.append("username", $("#uname").val());
$.ajax({
method: 'POST',
url: 'URL',
data: fd,
// 上传文件不需要吧data转换为字符串
// 不要转成字符串key=value&key=value&key=value格式
processData: false,
// 防止JQ对内容类型操作, 直接二进制流方式上传(保证是multipart/form-data)
contentType: false,
success: function (res) {
console.log(res)
}
})
})
// 总结:
// JQ提供方法 $("form标签").serialize() 收集标签里每个name属性的值和value的值然后返回一个字符串
// 1.0 声明变量 - 定义获取当前页面评论数据 的方法
var nowPage = 1; // 当前要第几页数据
var allPage; // 一共几页
// 1.1 获取铺设评论列表区
function getCommentList() {
// 1.2 调用接口 - 传递相应参数给后台 - 获取数据
$.ajax({
method: 'GET',
url: `URL?page=${
nowPage}&appkey=b7fc2560-5632-4da5-b625-58cff58c6b31`,
success: function (res) {
// 1.3 判断不是200证明报错 - 提示消息
if (res.status !== 200) return alert(res.msg)
// 1.4 保存当前一共有多少页
allPage = res.allPage;
// 1.5 先清空当前列表页面 - 重新铺设
$('#cmt-list').empty();
// 1.6 遍历铺设这次获取回来的数据
$(res.data).each(function (i, item) {
$('#cmt-list').append($(`
${
item.id}>删除
评论时间:${
item.time}
评论人:${
item.username}
${
item.content} `));
})
// 1.7 设置页码
$("#pageShow").html(nowPage);
}
})
}
// 1.8 获取此页的数据
getCommentList();
// 1.9 绑定上一个按钮/下一个按钮点击事件
$("#last").on("click", function () {
if (nowPage > 1) nowPage--;
getCommentList()
})
$("#next").on("click", function () {
if (nowPage < allPage) nowPage++;
getCommentList()
})
// 2.0 点击发布事件
$(function () {
$('#formAddCmt').submit(function (e) {
e.preventDefault()
// 2.1 获取表单上的内容形成key=value&key=value字符串
var data = $(this).serialize()
// 2.2 拼接我的授权码
data += "&appkey=b7fc2560-5632-4da5-b625-58cff58c6b31";
// 2.3 post发送数据给后台
$.post('URL', data, function (res) {
if (res.status !== 201) {
return alert('发表评论失败!' + res.msg);
}
// 2.4 发送成功后, 重新获取数据铺设页面
nowPage = 1;
getCommentList();
// 2.5 复位表单输入框
$('#formAddCmt')[0].reset()
})
})
})
// 3.0 事件委托 - 给所有删除绑定绑定点击事件
$("#cmt-list").on("click", ".del", function () {
// 3.1 去上面给删除标签绑定数据对应id, 点击获取评论对应唯一性的id
var theId = $(this).attr("theid");
// 3.2 调用删除接口 - 让后台删除这个数据
$.ajax({
method: 'GET',
url: `URL?id=${
theId}&appkey=b7fc2560-5632-4da5-b625-58cff58c6b31`,
success: function (res) {
// 3.3 如果不是200状态码, 代表删除失败给个提示, 阻止代码继续往下走
if (res.status !== 200) return alert(res.msg);
// 3.4 如果上面if进不去就走这里, 保存当前最大页码(因为当前页没数据了得自动回上一页)
allPage = res.allPage;
if (nowPage > allPage) nowPage = allPage;
// 3.5 设置页码 - 重新获取数据 - 铺设当前页面
getCommentList();
}
})
})
如有不足,请多指教,
未完待续,持续更新!
大家一起进步!