Ajax工作原理
1.http网络传输协议 :规定 前后端交互的 数据传输格式
协议 : 规定 前后端交互的数据传输格式
2.http协议组成两个部分
2.1前端 必须发送 请求报文格式
2.2后端 必须响应 响应报文格式
3.请求报文格式组成
(1) 请求行 : 请求方法和请求地址
(2)请求头 : 浏览器 告诉 服务器 ,我应该发给你的数据是什么
(3)请求体 : 请求参数 payload
4 ajax原理 ,设置请求报文
*发送ajax的过程就是设置请求报文
(1)响应行 响应状态码 +服务器IP地址
(2)响应头 服务器告诉 浏览器 我给你的数据是什么格式
(3)响应体 服务器响应数据 response
常见的几种状态码
****经典面试题 请求说出你所知道的常见的几种状态码
2xx (绿色)
200请求成功
204:post传输
3xx(黄色) 重定向(服务器修改浏览器地址)
302 :重定向,服务器主动修改浏览器地址
304 :客户端执行了GET,但是文件未变化
4xx(红色) 前端问题
400:参数错误
404:路径错误
401 :未验证身份
403 :服务器拒绝访问(没有权限) 会员
413 : 文件过大
422:参数错误
5xx(红色) :服务器问题
500 :服务器出问题
503 :服务器维护或者超载
请求报文
响应报文
网页从输入url到呈现过程
网页从输入url到呈现过程
1.DNS解析 :把域名 解析成 IP地址
2.TCP三次握手 : 保证http传输的安全可靠
第一次 浏览器 ->服务器 (你能听到我说话吗,验证浏览器发送)
第二次 服务器 -> 浏览器 (我听到了,你能听到我说话吗,验证服务器接收,服务器发送)
第三次 浏览器 -> 服务器(我也听到你说话了,验证浏览器接收)
3.HTTP连接
(1) 客户端发送请求
(2) 服务器处理请求
(3)服务器响应请求
4.渲染引擎渲染 :
(1)解析html :将得到dom树
(2)解析css :将得到样式树
(3)将dom树 + 样式树 合并成 渲染树
(4)绘制渲染树
(5)呈现页面
TCP三次握手
.TCP三次握手 : 保证http传输的安全可靠
第一次 浏览器 ->服务器 (你能听到我说话吗,验证浏览器发送)
第二次 服务器 -> 浏览器 (我听到了,你能听到我说话吗,验证服务器接收,服务器发送)
第三次 浏览器 -> 服务器(我也听到你说话了,验证浏览器接收)
渲染引擎渲染
(1)解析html :将得到dom树
(2)解析css :将得到样式树
(3)将dom树 + 样式树 合并成 渲染树
(4)绘制渲染树
(5)呈现页面
案例 -文件上传
1.1 file表单, 默认自带点击事件,作用是选择文件
1.2 上传文件‘必须’要使用原生内置的FormData对象
(1)文件需要设置单独的请求头 : multipart/form-data
(2)文件以二进制方式传输(文本是utf8编码,但是文件不是)
1.3 file表单有一个特殊的事件onchange事件 : 用户选择了文件就会执行
/*文件上传思路总结
1. 给file表单注册onchange事件
* 当用户选择图片之后执行
2. 获取用户选择的文件
*let file= this.files[0]
3. 使用FormData处理文件
let浮动=new FormData()
fd.append('参数名',文件对象)
* 只有FormData才可以上传文件
4. 发送ajax请求
* 文件上传请求方法一定是post, 且请求参数必须为 FormData对象
(1)formdata会自动帮你的请求头设置成文件请求头 :
(2)formdata 会自动帮你的文件转成 二进制
*/
<script src="./lib/axios.js"></script>
<script>
/*文件上传思路总结
1. 给file表单注册onchange事件
* 当用户选择图片之后执行
2. 获取用户选择的文件
*let file= this.files[0]
3. 使用FormData处理文件
let浮动=new FormData()
fd.append('参数名',文件对象)
* 只有FormData才可以上传文件
4. 发送ajax请求
* 文件上传请求方法一定是post, 且请求参数必须为 FormData对象
(1)formdata会自动帮你的请求头设置成文件请求头 :
(2)formdata 会自动帮你的文件转成 二进制
*/
// 给file表单注册onchange事件
document.querySelector('#iptFile').addEventListener('change',function(){
// this :file表单
// 2.获取用户选择的文件
console.log(this.files);
let file=this.files[0]
//3 文件数据必须要使用内置对象 FormData
// (1)文件请求头不一样 :multipart/form-data
// *formdata会自动帮你设置请求头
// (2) 文件格式是 二进制传输
// *formdata 会自动把你的文件编程二进制传输
let fd=new FormData()
// 追加参数 fd.append('参数名',文件数据)
fd.append('avatar',file)
// 4.发送ajax设置参数为fd
axios({
url:'http://www.liulongbin.top:3009/api/upload/avatar',
method:'post',
/* 细节 这里参数直接写浮动,千万不要{fd},因为fd本身就是对象类型 ,不需要单独{}包起来 */
data: fd,
}).then(res=>{
//成功回调
console.log(res)
// 渲染图片
document.querySelector('img').src=`http://www.liulongbin.top:3009${res.data.url}`
})
})
</script>
自定义头像上传按钮
(1)设置file表单为hidden
(2)给自定义按钮注册点击事件:触发file表单点击
第二种:
(1)label标签的for属性,设置成file表单的id 此时点击label就相当于点击file表单
label的作用是让某个制定的标签被选中
/*自定义文件上传按钮思路
第一种 :自定义按钮
(1)隐藏file表单
(2)给自定义按钮添加一个点击事件
(3)点击按钮的时候,触发 file表单的点击
第二种 :自定义图标
(1)把你的自定义图标放入label标签中
(2)label标签for属性,值是表单的id ,只要点击了label就相当于点击了表单
*/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>案例-头像上传</title>
<link rel="stylesheet" href="./lib/bootstrap-v4.6.0.css" />
<style>
.thumb-box {
text-align: center;
margin-top: 50px;
}
.thumb {
width: 250px;
height: 250px;
object-fit: cover;
border-radius: 50%;
}
#btnChoose{
border-radius: 20px;
background-image: linear-gradient(45deg,#DC1010, #90ED5A, #2F57E8);
}
</style>
</head>
<body>
<a href="http:www.baidu.com">111</a>
<div class="thumb-box">
<!-- 头像 -->
<!-- *** -->
<label for="iptFile">
<img src="./images/cover.jpg" class="img-thumbnail thumb" alt="" />
</label>
<div class="mt-2">
<!-- 文件选择框 -->
<!-- accept 属性表示可选择的文件类型 -->
<!-- image/* 表示只允许选择图片类型的文件 -->
<input
type="file"
id="iptFile"
accept="image/*"
style="display: none"
/>
<br />
<!-- 选择头像图片的按钮 -->
<button class="btn btn-primary" id="btnChoose">
选择 & 上传图片
</button>
</div>
</div>
<script src="./lib/axios.js"></script>
<script>
/*自定义文件上传按钮思路
第一种 :自定义按钮
(1)隐藏file表单
(2)给自定义按钮添加一个点击事件
(3)点击按钮的时候,触发 file表单的点击
第二种 :自定义图标
(1)把你的自定义图标放入label标签中
(2)label标签for属性,值是表单的id ,只要点击了label就相当于点击了表单
*/
document.querySelector('#btnChoose').addEventListener('click',function(){
// 模拟用户点击表单即可 :相当于点击这个按钮,就是点击表单
document.querySelector('#iptFile').click()
})
/*
*/
document.querySelector('#iptFile').addEventListener('change',function(){
console.log(this.files);
let file=this.files[0]
//3 文件数据必须要使用内置对象 FormData
// (1)文件请求头不一样 :multipart/form-data
// formdata会自动帮你设置请求头
// (2)
let fd=new FormData()
fd.append('avatar',file)
// 4.发送ajax设置参数为fd
axios({
url:'http://www.liulongbin.top:3009/api/upload/avatar',
method:'post',
data: fd,
}).then(res=>{
//成功回调
console.log(res)
document.querySelector('img').src=`http://www.liulongbin.top:3009${res.data.url}`
})
})
</script>
</body>
</html>
下拉展示更多案例
下拉加载更多功能
(1)声明全局变量 : index记录当前页数 arr所有的列表
(2)页面注册滚动事件
计算页面最大滚动距离 = 页面内容高度 -页面可视化高度
(3)封装 加载列表的ajax,接收一个页码作为参数 const getHeroList=index=>{}
(4)当滚动到最底部的时候,index++
(5)加载列表(调用函数) getHeroList(index)
*服务器返回数据之后,需要加到arr中再渲染 :arr.push(...res.data.list)
let index=1
let arr=[]
// 节流第一步 :声明开关默认值true
let flag=true
// (2)给页面注册滚动条事件
window.onscroll=function(){
/*节流第二步:判断开头 ,如果开关是true,则触发事件 + 开关改为false */
if(flag){
// 判断是否滚动到最底部
/* 页面最大滚动距离 scrollTop = 页面内容高度 scrollHight - 页面可视区域高度clientHeight*/
let maxTop = document.documentElement.scrollHeight - document.documentElement.clientHeight
let scrollTop = document.documentElement.scrollTop
/* 如果做了节流处理,这里最好不要完全碰到底部才请求下一页
因为有可能你碰到底部的时候,刚好flag是false,不会执行的
像京东 : 如果有节流的话, 一般离底部大概100px的位置就会请求下一页 */
if(scrollTop>= maxTop -100){
index++
console.log(index);
getHeroList(index)
}
// console.log(index);
}
}
// 节流 只要触发事件事件 .开关改为false
flag =false
/* 节流 开启定时器.节流时间后,把开关改为true*/
setTimeout(function(){
flag=true
},200)
// 页面一加载,渲染第一页数据
getHeroList(1)
详细参考
<!-- 导入axios -->
<script src="./lib/axios.js"></script>
<script>
// 页面一开始加载,ajax请求英雄列表
const getHeroList=index=>{
axios({
url: 'https://autumnfish.cn/api/cq/page',
method: 'get',
params: { pageNum: index, pageSize: 20 }
}).then(res => {
//成功回调
console.log(res)
// 先追加到全局数组
arr.push(...res.data.list)
// 渲染数组
renderData(arr)
})
}
/* 封装渲染函数 */
const renderData = arr => {
document.querySelector('tbody').innerHTML = arr.map(item => `
<tr>
<td><img src="${item.icon}" alt="" /></td>
<td>${item.name}</td>
<td>${item.skill}</td>
</tr>`).join('')
}
/*
2.输入框keydown
2.1判断enter键
2.2获取输入框内容
2.3发送ajax
2.4服务器响应渲染数据
*/
document.querySelector('.search').addEventListener('keydown', function (e) {
if (e.key == 'Enter') {
// 获取输入框内容
// let query=document.querySelector('.search').value
let query = this.value
axios({
url: 'https://autumnfish.cn/api/cq',
method: 'get',
params: { query }
}).then(res => {
if(!res.data.list){
return alert('已经到最低了')
}
//成功回调
console.log(res)
renderData(res.data.list)
})
}
})
/*
下拉加载更多功能
(1)声明全局变量 : index记录当前页数 arr所有的列表
(2)页面注册滚动事件(***记得把wrap的那个fixed定位注释掉)
计算页面最大滚动距离 = 页面内容高度 -页面可视化高度
(3)封装 加载列表的ajax,接收一个页码作为参数 const getHeroList=index=>{}
(4)当滚动到最底部的时候,index++
(5)加载列表(调用函数) getHeroList(index)
*服务器返回数据之后,需要加到arr中再渲染 :arr.push(...res.data.list)
*/
let index=1
let arr=[]
// 节流第一步 :声明开关默认值true
let flag=true
// (2)给页面注册滚动条事件
window.onscroll=function(){
/*节流第二步:判断开头 ,如果开关是true,则触发事件 + 开关改为false */
if(flag){
// 判断是否滚动到最底部
/* 页面最大滚动距离 scrollTop = 页面内容高度 scrollHight - 页面可视区域高度clientHeight*/
let maxTop = document.documentElement.scrollHeight - document.documentElement.clientHeight
let scrollTop = document.documentElement.scrollTop
/* 如果做了节流处理,这里最好不要完全碰到底部才请求下一页
因为有可能你碰到底部的时候,刚好flag是false,不会执行的
像京东 : 如果有节流的话, 一般离底部大概100px的位置就会请求下一页 */
if(scrollTop>= maxTop -100){
index++
console.log(index);
getHeroList(index)
}
// console.log(index);
}
}
// 节流 只要触发事件事件 .开关改为false
flag =false
/* 节流 开启定时器.节流时间后,把开关改为true*/
setTimeout(function(){
flag=true
},200)
// 页面一加载,渲染第一页数据
getHeroList(1)
</script>
函数防抖与节流
函数防抖
1.函数防抖 : 单位时间内,频繁触发事件,只会触发最后一次
2.经典应用场景 : 输入框输入事件 oninput
3.防抖流程 :
(1)声明全局变量存储定时器ID
(2)每一次触发事件的时候,先清除上一次定时器
(3)开启本次 防抖定时器
<script>
/*
1.函数防抖 : 单位时间内,频繁触发事件,只会触发最后一次
2.经典应用场景 : 输入框输入事件 oninput
3.防抖流程 :
(1)声明全局变量存储定时器ID
(2)每一次触发事件的时候,先清除上一次定时器
(3)开启本次 防抖定时器
*/
//(1)声明全局变量存储定时器ID
let timeID =null
document.querySelector('input').addEventListener('input',function(){
// 没触发一次事件的时候,先清除上一次定时器
clearTimeout(timeID)
// (3)开启本次 防抖定时器
/*
定时器中function :指向 window
箭头函数 :没有this,访问上级this,指向事件源
*/
timeID=setTimeout(()=>{
console.log(`发送ajax请求:${this.value}`);
},300)
})
</script>
函数节流
1.函数防抖 : 单位时间内,频繁触发事件,只会触发一次
2.经典应用场景 :解决事件高频触发 滚动条事件,鼠标移动
3.节流思路 :
(1) 恒明一个全局开关 let flag=true
(2) 触发事件的时候,判断开关
如果是true :触发事件,吧开关改为false
如果是false :不触发事件
(3)开启节流定时器,在节流事件之后把开关改为true
<script>
/*
1.函数防抖 : 单位时间内,频繁触发事件,只会触发一次
2.经典应用场景 :解决事件高频触发 滚动条事件,鼠标移动
3.节流思路 :
(1) 恒明一个全局开关 let flag=true
(2) 触发事件的时候,判断开关
如果是true :触发事件,吧开关改为false
如果是false :不触发事件
(3)开启节流定时器,在节流事件之后把开关改为true
*/
let flag=true
let i=1
window.onscroll=function(){
// (2) 触发事件的时候,判断开关
if(flag){
flag=false
console.log(`滚动事件触发次数${i++}`);
// (3)开启节流定时器,在节流事件之后把开关改为true
setTimeout(function(){
flag=true
},300)
}
}
// 鼠标移动
// let j=1
// window.onmousemove=function(){
// console.log(`鼠标滚动触发次数${j++}`);
// }
</script>
三种高度 offsetHeight scrollHeight clientHeight
offsetHight 盒子自身的高度
scrollHight 盒子内容的高度
clientHight 盒子视口的高度
scrollTop 页面卷出去的距离
<style>
div{
width: 80px;
height: 200px;
border: 10px solid red;
padding: 20px;
overflow: auto;
}
</style>
</head>
<body>
<div class="box">
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
程序员大前端
</div>
<script>
let box = document.querySelector('.box')
console.log( box.offsetHeight )//盒子自身高度 + 位置
console.log( box.scrollHeight )//盒子内容高度 + 位置
console.log( box.clientHeight )//盒子可视区域高度
</script>