知识点补充
配置基地址
- 新建 baseAPi.js
// ajaxPrefilter 方法注册了一个回调函数
// 此回调函数 会在使用 jq 的异步请求方法 前调用
// 并jq的请求的配置对象传给option
// 在回调函数里,就可以拿到 配置对象的url,为其添加上基地址
$.ajaxPrefilter(function(option) {
option.url = 'http://api-breakingnews-web.itheima.net' + option.url;
})
- 在login.html文件中,在login.js文件前引入baseAPi.js
<script src="/assets/lib/jquery.js"></script>
<!-- 导入基地址文件 -->
<script src="/assets/js/baseAPI.js"></script>
<script src="/assets/js/login.js"></script>
- 在login.js文件中,发起的ajax请求,url就可以不写基地址
$.ajax({
method: 'post',
url: '/api/login',
data: data,
success: function(res) {});
}
})
1. 浏览器服务器交互原理
- IP:在互联网上 电脑的 唯一标识(相当于 门牌号)
- 端口(Port):是 一台电脑中 为 和网络通信的程序 设置的 "编号ID"(相当于 人名)
1.1 浏览器服务器交互
1.2 请求报文和响应报文
1.2.1 请求报文
1.2.2 响应报文
1.3 URL地址
UniformResourceLocator 统一资源定位符
2. ajax
为什么要用ajax?
- 用户体验好:因为不需要整个页面都刷新,所以不会影响用户在浏览器的操作
- 节约资源:因为不需要整个页面刷新,节约了网络流量,减少了页面重绘的面积和次数
2.1 什么是ajax
Ajax 的全称是 Asynchronous JavaScript And XML(异步 JavaScript 和 xml)
通俗理解:在网页中利用 XMLHttpRequest 对象和服务器进行数据交互的方式,就是Ajax。
突出的特点:当前网页没有刷新、没有跳转。
2.2 $.get
$.get(url,[data],[callback]) get方式请求,用于获取数据
- 浏览器请求的数据放在url里面
- 服务器响应的的数据 放在响应报文体里
- 浏览器发送请求报文的格式 和 服务器解析报文都是符合http协议的
- 不带参数的请求
- 带参数的请求
本质:就是将 get 方法的 第二个参数对象,转成 键值对字符串 添加到 url ? 后面!
2.3 $.post
$.post(url,[data],[callback]) post方式请求,用于提交数据
- 数据 是 放在 请求报文体 中 传给 服务器的
2.3 $.ajax
$.ajax() 比较综合,既可以获取数据,又可以提交数据
$.ajax({
type: 'GET',
url: 'http://www.liulongbin.top:3006/api/getbooks',
data: {
id: 1
},
success: function(res) {
console.log(res)
}
})
2.4 接口
使用 Ajax 请求数据时,被请求的 URL 地址,就叫做 数据接口(简称接口)。同时,每个接口必须有请求方式。
服务器端提供的一个方法,我们通过浏览器端去调用服务器的方法
2.5 阻止表单默认提交
// 阻止按钮 默认触发表单默认提交的行为,因为表单提交,整个页面会重新渲染,会造成页面刷新,一般表单的提交会自己再设置,不默认提交
e.preventDefault();
3. Form表单
表单在网页中主要负责 数据采集功能。
3.1 form标签的属性
-
action(收件地址)
- 规定当提交表单时,向何处发送表单数据。
- 属性的值:后端提供的一个URL地址,这个URL地址专门负责接收表单提交过来的数据。
- 未指定
action属性值的清空下,action的默认值为当前页面的URL地址 - 当提交表单后,会立即跳转到
action属性指定的URL地址
-
target
target属性用来规定 在何处打开action URL
-
method
- 规定 以何种方式 把表单数据提交到 action URL
- get 方式适合用来提交少量的,简单的数据
- post 方式适合用来提交大量的,复杂的,或包含文件上传的数据
-
enctype
- 规定在 发送表单数据之前如何对数据进行编码
- 规定在 发送表单数据之前如何对数据进行编码
3.2 表单提交的缺点
缺点:
<form>表单同步提交后,整个页面会发生跳转,跳转到 action URL 所指向的地址,用户体验很差<form>表单同步提交后,页面之前的状态和数据会丢失
解决方案: 表单只复杂采集数据,Ajax负责将数据提交到服务器
3.3 阻止表单的默认提交
$('#f1').on('submit', function(e) {
alert('监听到了表单的提交事件2')
e.preventDefault()
})
3.3 获取表单数据jq.serialize()
**注意:**在使用 serialize() 函数快速获取表单数据时,必须为每个表单元素添加 name 属性
<form action="/login" id="f1">
<input type="text" name="user_name" />
<input type="password" name="password" />
<button type="submit">提交</button>
</form>
$('#f1').on('submit', function(e) {
// 阻止表单的默认提交行为
e.preventDefault();
// 获取表单的数据
let data = $(this).serialize();
console.log(data); // user_name=用户名值&password密码的值
})
3.4 dom.reset()快速清空表单文本框
注意:reset()是dom对象的方法,所以要将jq对象转换为dom对象
$('#formAddCmt')[0].reset()
$('#formAddCmt').on('submit', function(e) {
// 阻止默认提交
e.preventDefault();
// 获取表单元素的数据
let data = $(this).serialize();
$.post('http://www.liulongbin.top:3006/api/addcmt', data, function(res) {
if (res.status != 201) return alert('发表评论失败');
// 更新列表
upload();
// 注意this的指向
// 自动清空文本空内容
$('#formAddCmt')[0].reset()
})
})
4. 模板引擎
模板引擎,它可以根据程序员指定的 模板结构 和 数据,自动生成一个完整的HTML页面
好处
- 减少了字符串的拼接操作
- 使代码结构更清晰
- 使代码更易于阅读与维护
4.1 art-template
4.1.1 使用步骤
-
导入
art-template<script src="./lib/template-web.js"></script> -
准备html容器
<div id="container"></div> -
定义数据data
-
定义模版
<script type="text/html" id="tpl-user"> <h1>{{name}} ------ {{age}}</h1> </script> -
调用template函数
var htmlStr = template('tpl-user', data) -
渲染html结构
$('#container').html(htmlStr)
示例
<!-- 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 中 -->
<!-- 注意type要为html,这是一个script标签,而不是当作js去执行 -->
<script type="text/html" id="tpl-user">
<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 y + '-' + m + '-' + d
}
// 2. 定义需要渲染的数据
var data = {
name: 'zs',
age: 20,
test: '<h3>测试原文输出</h3>',
flag: 1,
hobby: ['吃饭', '睡觉', '写代码'],
regTime: new Date()
}
// 4. 调用 template 函数
var htmlStr = template('tpl-user', data)
console.log(htmlStr);
// 5. 渲染HTML结构,放到html容器里面
$('#container').html(htmlStr)
</script>
</body>
</html>
4.1.2 标准语法
- 原文输出
// 如果包含html标签,保证HTML标签被正常渲染
{{@ value}}
- 条件输出
{{if v1}}
...
{{else if v2}}
...
{{/if}}
- 循环输出
{{each arr}}
<li>索引是:{{$index}},循环项是:{{$value}}</li>
{{/each}}
- 过滤器
案例-格式化时间过滤器
-
定义数据
var data = { regTime: new Date() } -
定义过滤器
// 定义处理时间的过滤器 template.defaults.imports.dateFormat = function (date) { var y = date.getFullYear() var m = date.getMonth() + 1 var d = date.getDate() return y + '-' + m + '-' + d } -
在模板引擎中使用过滤器
<script type="text/html" id="tpl-user"> <h3>{{regTime | dateFormat}}</h3> </script>
4.2 模版引擎的实现原理
- 通过exec()提取出自己想要的字符串
var str = '<div>我是{{name}}</div>'
// 正则表达式中 () 包起来的内容表示一个分组,为了提取出"name"
var pattern = /{{([a-zA-Z]+)}}/
var result = pattern.exec(str)
console.log(result)
- 再通过循环,挨个将提取出的属性名(如name),去data中拿到对应的属性值
data[patternResult[1]],并将其str.replace('被替换的值','去替换的值')到标签中
var data = { name: '张三', age: 20 }
var str = '<div>{{name}}今年{{ age }}岁了</div>'
// \s---匹配>=0的空格
var pattern = /{{\s*([a-zA-Z]+)\s*}}/
var patternResult = null
while (patternResult = pattern.exec(str)) {
str = str.replace(patternResult[0], data[patternResult[1]])
}
console.log(str)
4.3 自定义简易的模版引擎
/template.js/
function template(id, data) {
var str = document.getElementById(id).innerHTML
var pattern = /{{\s*([a-zA-Z]+)\s*}}/
var pattResult = null
while (pattResult = pattern.exec(str)) {
str = str.replace(pattResult[0], data[pattResult[1]])
}
return str
}
/调用自己的模版引擎.html/
<script src="./js/template.js"></script>
</head>
<body>
<div id="user-box"></div>
<script type="text/html" id="tpl-user">
<div>姓名:{{name}}</div>
<div>年龄:{{ age }}</div>
<div>性别:{{ gender}}</div>
<div>住址:{{address }}</div>
</script>
<script>
// 定义数据
var data = { name: 'zs', age: 28, gender: '男', address: '北京顺义马坡' }
// 调用模板引擎
var htmlStr = template('tpl-user', data)
// 渲染HTML结构
document.getElementById('user-box').innerHTML = htmlStr
</script>
</body>
5. XMLHttpRequest
XMLHttpRequest(简称xhr)是浏览器提供的Javascript对象,通过它,可以请求服务器上的数据资源
jQuery中的 Ajax 函数,就是基于xhr对象封装出来的
5.1 使用xhr发起GET请求
注意:
open和send最好写在最后,避免不必要的bug,且open要写在send之前!!
// 1. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 4. 监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
// readyState--监听xh对象的请求状态 status--服务器的响应状态
if (xhr.readyState === 4 && xhr.status === 200) {
// 获取服务器响应的数据
console.log(xhr.responseText)
}
}
// 2. 调用 open 函数
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks')
// 3. 调用 send 函数
xhr.send()
1. readyState 属性-表示当前 Ajax 请求所处的状态
2. status 属性 - 响应报文中 第一行的 http协议状态码
- 200 - 服务器运行正常
- 404 - 服务器 没有 要请求的url
- 500 - 服务器 报错
3. responseText 属性 - 响应报文体数据(取出来是 文本字符串)
- 注意:一般 将它 转成 js对象使用
let res = JSON.parse(xhr.responseText)
5.1.1 发起带参数的GET请求
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks?id=1')
5.1.2 查询字符串
查询字符串(URL 参数)是指在 URL 的末尾加上用于向服务器发送信息的字符串(变量)。
url?id=1&bookname=目送
5.1.3 GET请求携带参数的本质
无论使用
$.ajax(),还是使用$.get(),又或者直接使用xhr对象发起GET请求,当需要携带参数的时候, 本质上,都是直接将参数以查询字符串的形式,追加到 URL 地址的后面,发送到服务器的。
5.2 URL编码与解码
URL地址中,只允许出现英文相关的字母、标点符号、数字所以必须对中文字符进行编码(转义)。
浏览器会自动对 URL 地址进行编码操作
var str = '黑马程序员';
// 编码 encodeURI(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('----------');
// 解码 decodeURI(str)
var str3 = decodeURI('%E9%BB%91%E9%A9%AC');
console.log(str3); // 黑马
5.3 使用xhr发起POST请求
// 1. 创建 xhr 对象
var xhr = new XMLHttpRequest()
// 2. 调用 open 函数
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. 监听事件
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText)
}
}
6. 数据交换格式
服务器端与客户端之间进行数据传输与交换的格式。(例:XM和JSON)
6.1 XML
EXtensible Markup Language,即可扩展标记语言,和HTML类似,都是一种标记语言
-
HTML被设计用来描述网页上的内容,是网页内容的载体 -
XML被设计用来传输和存储数据,是数据的载体XML格式臃肿,和数据无关的代码多,体积大,传输效率低- 在
Javascript中解析XML比较麻烦
6.2 JSON
JavaScript Object Notation,即“JavaScript 对象表示法”本质:用字符串来表示
Javascript对象数据或数组数据,是字符串。作用:**在计算机与网络之间存储和传输数据。
JSON是一种轻量级的文本数据交换格式,在作用上类似于XML,专门用于存储和传输数据- 比
XML更小、更快、更易解析。
6.2.1 语法注意事项
① 属性名必须使用双引号包裹
② 字符串类型的值必须使用双引号包裹
③ 数据类型只能是:数字、字符串、布尔值、null、数组、对象6种类型。
④ JSON 中不能写注释
⑤ JSON 的最外层必须是对象或数组格式
⑥ 不能使用 undefined 或函数作为 JSON 的值
6.2.2 JSON和JS
JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。
// 对象
let obj={a:'hello' , b:'world'}
// json字符串
let json=' {"a":"hello" , "b":"world"} '
- JSON 字符串转换为 JS 对象,
JSON.parse(),反序列化 - JS 字符串转换为 JSON 对象,
JSON.stringfy(),序列化
6.3 封装Ajax函数
/测试页面.html/
<script src="./js/itheima.js"></script>
itheima({
method: '',
url: '',
data: {},
success:function(res){}
})
/itheima.js/
# 1. 处理data参数,把传入的对象,转为json字符串
/*** 处理 data 参数
* @param {data} 需要发送到服务器的数据
* @returns {string} 返回拼接好的查询字符串 name=zs&age=10
*/
function resolveData(data) {
var arr = []
for (var k in data) {
var str = k + '=' + data[k]
arr.push(str)
}
return arr.join('&');
}
# 2. 定义itheima函数
function itheima(options) {
var xhr = new XMLHttpRequest();
// 把外界传递过来的参数对象,转换为 查询字符串
var qs = resolveData(options.data)
// 判断请求类型,相应地进行send请求操作
if (options.method.toUpperCase() === 'GET') {
// 发起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);
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4 && xhr.status === 200) {
var result = JSON.parse(xhr.responseText)
options.success(result)
}
}
}
7. XMLHttpRequest Level2的新特性
- 旧版XMLHttpRequest的缺点
-
只支持文本数据的传输,无法用来读取和上传文件
-
传送和接收数据时,没有进度信息,只能提示有没有完成
-
- 新功能
-
可以设置 HTTP 请求的时限
-
可以使用
FormData对象管理表单数据 -
可以上传文件
-
可以获得数据传输的进度信息
-
7.1 设置 HTTP 请求时限 timeout
<script>
var xhr = new XMLHttpRequest()
// 设置 超时时间,最长等待时间设为 30 毫秒
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>
7.2 FormData 对象管理表单数据
HTML5新增了FormData对象提交表单推荐:
使用form的
submit事件,因为form中可能存在多个提交按钮,这样不论点击哪个按钮,都会触发表单的提交事件
- 使用FormData主要是为了
上传文件, - 只能给
post使用 - 直接获取form表单数据
var fd = new FormData(form), 必须给input表单添加name属性; - 如果逐个添加表单数据,
var fd = new FormData(); fd.append('uname', 'zs'),此时的 属性名uname就相当于name
7.2.1 提交表单数据
// 1. 新建 FormData 对象
var fd = new FormData()
// 2. 为 FormData 添加表单项
fd.append('uname', 'zs')
fd.append('upwd', '123456')
// 3. 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 4. 指定请求类型与URL地址
xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
// 5. 直接提交 FormData 对象,这与提交网页表单的效果,完全一样
xhr.send(fd)
7.2.2 获取表单数据 new FormData(dom)
-
jq方式:
$('#form1').serialize()可以直接获取form表单中带name属性的值 键值对格式 -
formDate方式:
new FormData(form)自动将表单数据填充到 创建formData对象中 formData数据格式
// 获取表单元素
var form = document.querySelector('#form1')
// 监听表单元素的 submit 事件
form.addEventListener('submit', function(e) {
e.preventDefault()
// 根据 form 表单创建 FormData 对象,会自动将表单数据填充到 FormData 对象中
var fd = new FormData(form)
var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://www.liulongbin.top:3006/api/formdata')
xhr.send(fd)
xhr.onreadystatechange = function() {}
})
7.3 上传文件
<body>
<form id="form1">
<!-- 1. 文件选择框 -->
<input type="file" id="file1" name="avatar" />
<!-- 2. 上传文件的按钮 -->
<button id="btnUpload">上传文件</button>
</form>
<br />
<!-- 3. img 标签,来显示上传成功以后的图片 -->
<img src="" alt="" id="img" width="800" />
<script>
let btn = document.querySelector('#btnUpload');
let file1 = document.querySelector('#file1');
let form1 = document.querySelector('#form1');
let img = document.querySelector('#img');
// 1.为表单添加提交事件
form1.addEventListener('submit', function(e) {
// 2.阻止表单的默认提交
e.preventDefault();
// 3.判断是否上传了图片*****
if (file1.files.length <= 0) return alert('请上传图片!');
// 4.通过this获取表单数据*****
let fd = new FormData(this); // FormData {}
let xhr = new XMLHttpRequest();
xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar');
xhr.send(fd);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status == 200) {
let data = JSON.parse(xhr.responseText);
// data: {message: "上传文件成功!", status: 200, url: "/uploads/1625309578020_f15c0f22d3a143dcae417640c14b4410.jpg"}
if (data.status == 200) {
// 将服务器返回的图片地址,设置为 <img> 标签的 src 属性
// 根路径+data.url*****
img.src = 'http://www.liulongbin.top:3006' + data.url;
} else {
// 上传失败
alert(data.message);
}
}
}
})
</script>
</body>
7.4 显示文件上传进度
7.4.1 计算文件上传进度
新版本的 XMLHttpRequest 对象中,可以通过监听 xhr.upload.onprogress 事件,来获取到文件的上传进度。语法格式如下:
// 创建 XHR 对象
var xhr = new XMLHttpRequest()
// 监听 xhr.upload 的 onprogress 事件
xhr.upload.onprogress = function(e) {
// e.lengthComputable 是一个布尔值,表示当前上传的资源是否具有可计算的长度
if (e.lengthComputable) {
// e.loaded 已传输的字节
// e.total 需传输的总字节
var percentComplete = Math.ceil((e.loaded / e.total) * 100)
}
}
7.4.2 动态设置到进度条上
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
// 1. 计算出当前上传进度的百分比
var percentComplete = Math.ceil((e.loaded / e.total) * 100)
$('#percent')
// 2. 设置进度条的宽度
.attr('style', 'width:' + percentComplete + '%')
// 3. 显示当前的上传进度百分比
.html(percentComplete + '%')
}
}
7.4.3 监听上传完成的事件
xhr.upload.onload = function() {
$('#percent')
// 移除上传中的类样式
.removeClass()
// 添加上传完成的类样式
.addClass('progress-bar progress-bar-success')
}
7.4.4 完整代码
<body>
<form id="form1">
<!-- 1. 文件选择框 -->
<input type="file" id="file1" name="avatar" />
<!-- 2. 上传文件的按钮 -->
<button id="btnUpload">上传文件</button>
</form>
<!-- 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>
$('#form1').on('submit', function(e) {
e.preventDefault();
// 判断是否上传了文件-------------------------------------------
// 只有dom对象才有 files属性 $('#file1').get(0)和($('#file1')[0]是一样的
if ($('#file1')[0].files.length <= 0) return alert('请上传文件!');
// 创建formdata对象,并将表单数据追加进去
let fd = new FormData(this);
// 创建异步对象-----------------
let xhr = new XMLHttpRequest();
// 监控文件上传进度-----------------------
xhr.upload.onprogress = uploadProgress;
// 监控 请求状态变化---------------------------
// 通过bind,为函数传入实参 xhr
xhr.onreadystatechange = stateChange.bind(null, xhr);
// 最好写在最后面,避免bug
xhr.open('POST', 'http://www.liulongbin.top:3006/api/upload/avatar')
xhr.send(fd);
})
function uploadProgress(e) {
if (e.lengthComputable) {
let percent = Math.ceil(e.loaded / e.total * 100) + '%';
$('#percent').css('width', percent).html(percent);
// 如果进度到了100%,则修改 进度条样式
if (percent == '100%') {
// 由于 上传完成后,进度条的动画要消耗时间
// 所以,0.5s后再将 改变进度条的样式
setTimeout(() => {
$('#percent').removeClass().addClass('progress-bar progress-bar-success');
}, 500);
}
}
}
function stateChange(xhr) {
if (xhr.readyState == 4 && xhr.status == 200) {
let data = JSON.parse(xhr.responseText);
// 上传成功,为img修改src属性
if (data.status == 200) {
$('#img').prop('src', 'http://www.liulongbin.top:3006' + data.url);
} else {
alert(data.message);
}
}
}
</script>
</body>
7.5 使用jquery发起上传文件的请求
$.ajax({
method: 'POST',
url: 'http://www.liulongbin.top:3006/api/upload/avatar',
data: fd,
// 不修改 Content-Type 属性,使用 FormData 默认的 Content-Type 值
contentType: false,
// 不对 FormData 中的数据进行 url 编码,而是将 FormData 数据原样发送到服务器
processData: false,
success: function(res) {
console.log(res)
}
})
8. axios
jquery提供dom操作 和 ajax操作;而axios只提供ajax操作
为什么要是要使用axios?
vue等框架不需要程序来操作dom,所以不需要使用jq,而是使用只提供ajax操作的axios库(axios更轻量化)
8.1 axios发起GET请求
axios.get('url', { params: { /*参数*/ } }).then(callback)
8.2 axios发起POST请求
axios.post('url', { /*参数*/ }).then(callback)
8.3 直接使用axios发起请求
axios({
method: '请求类型',
url: '请求的URL地址',
data: { /* POST数据 */ },
params: { /* GET参数 */ }
}).then(callback)
1.发起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: paramsData
}).then(function (res) {
console.log(res.data)
})
})
2.发起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)
})
})
9. 同源策略
9.1 同源
如果两个页面的协议,域名(IP-找服务器)和端口(80-找服务器中的程序)都相同,则两个页面具有相同的源。
同源策略(英文全称 Same origin policy)是浏览器提供的一个安全功能,不允许非同源的 URL 之间进行资源的交互。
9.2 跨域
什么是跨域:
同源指的是两个 URL 的协议、域名、端口一致,反之,则是跨域
跨域检查:
浏览器允许发起ajax跨域请求,但是,跨域请求回来的数据,会被浏览器检查,是否允许ajax跨域请求,如果否,就会拦截报错!
浏览器对跨域请求的拦截
实现跨域的解决方案:
-
**
JSONP:**出现的早,兼容性好(兼容低版本IE)。是前端程序员为了解决跨域问题,被迫想出来的一种临时解决方案。缺点是只支持GET请求,不支持POST请求。 -
**
CORS:**出现的较晚,它是W3C标准,属于跨域Ajax请求的根本解决方案。支持GET和POST请求。缺点是不兼容某些低版本的浏览器 -
服务器代理:服务器端不直接去发出跨域请求,而在服务器端设置一个代理(proxy),由服务器端向跨域下的代理发出请求,再将请求的结果返回到前端。
9.3 JSONP
<script>标签不受浏览器同源策略的影响,可以通过src属性,请求非同源的js脚本。
JSONP的实现原理: 通过<script>标签的src属性,请求跨域的数据接口,并通过函数调用的形式,接收跨域接口响应回来的数据
- 目的:为了异步获取服务器 接口 返回的数据
- 问题:浏览器存在 针对ajsx跨域请求 的检查
- 解决方案:不实用ajax发送异步请求,而是使用script标签来跨域请求,从而绕过浏览器针对ajax的跨域检查
/实现一个简单的jsonp/
// 定义一个`success`回调函数:
<script>
function success(data) {
console.log('获取到了data数据:')
console.log(data)
}
</script>
// 通过 `<script>` 标签,请求接口数据:
<script src="http://ajax.frontend.itheima.net:3006/api/jsonp?callback=success&name=zs&a
ge=20"></script>
注意:
JSONP 和 Ajax 之间没有任何关系,不能把 JSONP 请求数据的方式叫做 Ajax,因为 JSONP 没有用到XMLHttpRequest 这个对象
9.3.1 jq发送jsonp数据请求
默认情况下,使用 jQuery 发起 JSONP 请求,会自动携带一个
callback=jQueryxxx的参数,jQueryxxx是随机生成的一个回调函数名称
$.ajax({
url: 'http://ajax.frontend.itheima.net:3006/api/jsonp?name=zs&age=20',
// 如果要使用 $.ajax() 发起 JSONP 请求,必须指定 datatype 为 jsonp
dataType: 'jsonp',
// 发送到服务端的参数名称,默认值为 callback,一般不写保持默认值
jsonp: 'callback',
// 自定义的回调函数名称,默认值为 jQueryxxx 格式
jsonpCallback: 'abc',
success: function(res) {
console.log(res)
}
})
jQuery中JSONP的实现过程
jQuery 中的 JSONP,也是通过 <script> 标签的 src 属性实现跨域数据访问的,只不过,jQuery 采用的是动态创建和移除标签的方式,来发起 JSONP 数据请求。
-
在发起 JSONP 请求的时候,动态向
<header>中 append 一个<script>标签; -
在 JSONP 请求成功以后,动态从
<header>中移除刚才append进去的<script>标签;
9.4 缓存搜索记录
1.定义全局缓存对象
// 缓存对象
var cacheObj = {}
2.将搜索结果保存到缓存对象中
// 渲染建议列表
function getList(keyword) {
// ...省略其他代码
success(res){
// 先将 关键字k 和 建议列表数组value,添加到缓存对象中
cacheObj[keyword] = res;
// 再渲染模版结构
renderList(res);
}
}
3.优先从缓存中获取搜索建议
// 监听文本框的 keyup 事件
$('#ipt').on('keyup', function() {
// ...省略其他代码
// 在发起请求之前,先判断缓存中是否有数据
// 如果有,就不用去发送ajax请求,直接将缓存的数据渲染到页面中
if (cacheObj[keywords]) {
return renderSuggestList(cacheObj[keywords])
}
// 获取搜索建议列表
debounceSearch(keywords)
})
9.5 防抖
-
防抖策略(
debounce)是当事件被触发后,延迟n秒后再执行回调,如果在这n秒内事件又被触发,则重新计时。即:单位事件内计划执行某件事,一旦打断,则重新计时 -
**好处:**能够保证用户在频繁触发某些事件的时候,不会频繁的执行回调,只会被执行一次。
-
应用场景:
- 回城,一旦打断就重新计时
- 用户在输入框中连续输入一串字符时,可以通过防抖策略,只在输入完后,才执行查询的请求,这样可以有效减少请求次数(以最后一次触发开始计时为准),节约请求资源。
var timer = null // 1. 防抖动的 timer
function debounceSearch(keywords) { // 2. 定义防抖的函数
timer = setTimeout(function() {
// 发起 JSONP 请求
getSuggestList(keywords)
}, 500)
}
$('#ipt').on('keyup', function() { // 3. 在触发 keyup 事件时,立即清空 timer
clearTimeout(timer)
// ...省略其他代码
debounceSearch(keywords)
})
9.6 节流
- 节流策略(
throttle)单位时间内,不管触发多少次,都只执行一次
9.6.1 节流的应用场景
① 鼠标连续不断地触发某事件(如点击),只在单位时间内只触发一次;
② 懒加载时要监听计算滚动条的位置,但不必每次滑动都触发,可以降低计算的频率,而不必去浪费 CPU 资源;
9.6.2 鼠标跟随效果案例(节流阀)
// 假设 浏览器渲染图片耗时16ms 才能完成
// 所以鼠标没必要 在每次移动时 都重新设置图片的位置
// 因此 可以设置 每隔16ms再 设置一次图片的位置
$(function() {
// 1. 获取到图片
var angel = $('#angel');
// 步骤1. 定义节流阀
var timer = null;
// 2. 绑定 mousemove 事件
$(document).on('mousemove', function(e) {
// 步骤3:判断节流阀是否为空,如果不为空,则证明距离上次执行间隔不足16毫秒
if (timer) {
return
};
// 3. 设置图片的位置
// 步骤2:开启延时器
timer = setTimeout(function() {
$(angel).css('top', e.pageY - 40 + 'px').css('left', e.pageX - 40 + 'px')
console.log('ok');
// 当设置了鼠标跟随效果后,清空 timer 节流阀,方便下次开启延时器
timer = null;
}, 16)
})
})
10. HTTP
10.1 通信协议
Communication Protocol,指通信的双方完成通信所必须遵守的规则和约定。
通信双方采用约定好的格式来发送和接收消息,这种事先约定好的通信格式,就叫做通信协议。
10.2 HTTP协议
超文本传输协议(HyperText Transfer Protocol),规定了客户端与服务器之间进行网页内容传输时,所必须遵守的传输格式。
10.3 HTTP请求消息
客户端发起的请求叫做 HTTP 请求,客户端发送到服务器的消息,叫做 HTTP 请求消息,又称请求报文。
HTTP请求消息的组成部分
HTTP请求消息由请求行(request line)、请求头部(header) 、空行 和 请求体 4 个部分组成。
10.3.1 请求行
请求行由请求方式、URL 和 HTTP 协议版本 3 个部分组成,他们之间使用空格隔开。
10.3.2 请求头部
请求头部用来描述客户端的基本信息,从而把客户端相关的信息告知服务器。比如:User-Agent 用来说明当前是什么类型的浏览器;
Content-Type用来描述发送到服务器的数据格式;Accept 用来描述客户端能够接收什么类型的返回内容;Accept-Language用来描述客户端期望接收哪种人类语言的文本内容。
请求头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔
请求头部 – 常见的请求头字段
MDN
10.3.3 空行
最后一个请求头字段的后面是一个空行,通知服务器请求头部至此结束。
请求消息中的空行,用来分隔请求头部与请求体
10.3.4 请求体
请求体中存放的,是要通过 POST 方式提交到服务器的数据。
注意:只有 POST 请求才有请求体,GET 请求没有请求体!
10.4 HTTP响应消息
响应消息就是服务器响应给客户端的消息内容,也叫作响应报文。
HTTP响应消息由状态行、响应头部、空行 和 响应体 4 个部分组成,如下图所示:
10.4.1 状态行
状态行由 HTTP 协议版本、状态码和状态码的描述文本 3 个部分组成,他们之间使用空格隔开
10.4.2 响应头部
响应头部用来描述服务器的基本信息。响应头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔。
- 响应头部 – 常见的响应头字段
10.4.3 空行
在最后一个响应头部字段结束之后,会紧跟一个空行,用来通知客户端响应头部至此结束。
响应消息中的空行,用来分隔响应头部与响应体。
10.4.4 响应体
响应体中存放的,是服务器响应给客户端的资源内容。
10.5 HTTP的请求方法
10.6 HTTP响应状态码
HTTP Status Code,用来标识响应的状态。MDN官网
HTTP 状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字用来对状态码进行细分。
10.6.1 2** 成功相关的响应状态码
表示服务器已成功接收到请求并进行处理
10.6.2 3** 重定向相关的响应状态码
表示服务器要求客户端重定向,需要客户端进一步的操作以完成资源的请求
10.6.3 4** 客户端错误相关的响应状态码
表示客户端的请求有非法内容,从而导致这次请求失败。
10.6.4 5** 服务端错误相关的响应状态码
表示服务器未能正常处理客户端的请求而出现意外错误。