1 服务器相关的基础概念
1.1 服务器
服务器的本质也是一台电脑。
服务器的作用:
- 存储一个网站的文件(html,css,js,图片,音乐... )
- 提供网站的文件给用户
1.2 资源
资源代指服务器上存储的内容,通俗的讲,我们浏览网页时,从网络中看到的内容都叫资源
服务器上的每个资源,都对应着独一无二的URL地址
注意:通过在浏览器地址栏输入URL地址,去向服务器发起的请求本质上是一个get请求
2 network面板介绍
2.1 调接口时的一个时间轴
2.2 显示请求方式
2.3 查看请求状态
3 客户端与服务器通信的过程
客户端一般指浏览器
客户端与服务器的通信过程,分为请求-响应两个步骤,其中:
-
请求的概念:客户端通过网络去找服务器要资源的过程,叫做“请求”
-
响应的概念:服务器把资源通过网络发送给客户端的过程,叫做“响应”
4 同步和异步
1 同步:阻塞类型的代码执行方式
2 异步 非阻塞类型的代码执行方式
常见的异步有:
- 定时器 setInterval
- 延时器 setTimeout
- Ajax
- 事件绑定 addEventListner
- promise
5 什么是Ajax
Asynchronous JavaScript And XML(异步的js和xml)
5.1 生活中的Ajax
5.2 Ajax的三大关键
1 请求地址(URL)
告诉浏览器去哪个服务器地址和服务器交互数据
2 请求方式
让浏览器选择合适的方式和服务器交互
发起Ajax的5种请求方式
请求方式 | 描述 |
---|---|
post | 向服务器新增数据 |
get | 从服务器获取数据 |
delete | 删除服务器上的数据 |
put | 更新服务器上的数据--侧重于完整更新(例如更新用户的完整信息) |
patch | 更新服务器上的数据--侧重于部分更新(例如只更新用户的手机号) |
3 请求参数
不是必须,具体看接口文档说明
6 工作中使用Ajax的方式
1 原生底层的Ajax (比较少)
2 基于Ajax封装的js库(axios,jQuery)主流
3 面向现代浏览器的fetch
7 第一个axios实例
8 如何区分不同的请求方式携带参数写在data还是params
1 看文档
- Query 参数 写在url上或者params上
- body 参数 写在data 上
2 默认
-
get请求 -- url或者params
-
post请求 -- data
-
delete、put、patch 结合文档来看
-
delete 和 get 类似
-
put patch post 类似
3 试试就知道了!!!
9 接口数据的crud
9.1 获取接口数据的实现方式
这里先引入一个概念appkey
因为后面我们做项目不单单是调接口就完事了,更多是以下的业务情况
-
除了页面显示数据要调接口
-
在输入框输入值,点击搜索时,也要调接口,所以一般要封装一个render函数,可接收参数
-
页面一开始加载时,就调用render函数
-
点击搜索时也要调render函数,并且把输入框的值传过去。
代码如下
axios.defaults.baseURL ="http://www.itcbc.com:3006"
// 封装表格数据渲染函数
function render(bn) {
//每次调用时先清空表格的内容
tbody.innerHTML=""
let params = {}
//当调用函数不传参时,bn为undefined,执行这段代码,只给接口传appkey
if(!bn){
params = { appkey: "132000088"}
}else{
//当点击搜索时,调用这个函数,给这个函数传参为输入框的值,连同appkey传给接口
params = { bookname:bn, appkey: "132000088"}
}
axios.get("/api/getbooks",{params}).then((result) =>{
const arr = result.data.data
//根据返回的数据动态生成表格
arr.forEach(value => {
let tr = document.createElement("tr")
tr.innerHTML= `
<td>${value.id}</td>
<td>${value.bookname}</td>
<td>${value.author}</td>
<td>${value.publisher}</td>
<td>
<div class="operate">
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#myModal" data-id=${value.id}>编辑</button>
<button type="button" class="btn btn-danger" data-id=${value.id}>删除</button>
</div>
</td>
`
tbody.appendChild(tr)
});
})
}
// 一开始调用函数进行渲染
render()
9.2 新增接口数据的实现方式
一般的业务需求为:
点击新增按钮,有个弹窗,填好表单的值,点击确定时,会调用新增接口新增数据
需求分析:
1 因为弹窗的输入框个数不会少,所以要快速获取表单的值,而不能一个一个去获取,通过以下代码实现:
2 然后调用这个函数,给函数传表单DOM元素,把返回的值如果要拼接上其他参数就进行拼接,如果不用,就把这个返回值直接传给接口就行,记得调完接口成功新增数据之后,要再调用render函数,让页面显示最新的数据
9.3 删除接口的数据的实现方式
需求:(点击页面上的删除按钮,删除接口中当前行的数据,并刷新页面)
分析需求的一个实现方式:
1 首先要给删除按钮绑定事件,因为后面可能会添加新的数据,页面中的删除按钮会动态增加,不能直接去获取删除的dom元素,直接绑定事件,而是要通过事件委托的方式,给它的一个父元素table绑定事件,利用事件冒泡,实现动态的给删除按钮绑定事件
2 点击的时候,怎么获取当前行的一个id属性,把这个属性传给接口?就给删除按钮添加一个自定义属性data-id,给它赋值为接口的id值value.id,后面就可以通过e.target.dataset.id获取到当前行的一个id值
代码实现:
9.4 编辑接口的数据的实现方式
需求:(点击页面上的编辑按钮,把当前行的数据赋值给右边的表单,右边的表单修改完数据之后,点击确认编辑按钮,会修改左边的数据)
分析需求的一个实现方式:
1 点击编辑按钮 ,获取到被点击的按钮(事件委托的方式),把当前行的数据的id传给获取数据的接口----这里id拿的方式跟删除数据时拿id一个道理,把对应的数据显示到表单中,顺带给确认编辑按钮加一个自定义属性赋值为id,方便待会提交编辑时,能拿到id
2 修改完数据之后,点击确认编辑,把表单的数据传给接口,刷新页面
代码实现:
10 调接口出问题时,快速的调试方法
- 这些是后端对你请求接口的回应
- 这个标头是我们请求时的一些信息
- 这个载荷是我们请求接口时给接口传的参数
一般如果接口报200能调通,预览这里报不存在的接口,那么问题一般出现在你写的代码单词出错了,可能是请求的三要素:请求的地址,请求的方式,请求的参数 的代码单词写错了(注意请求方式是method不是methods,请求的URL地址 / 看有没有加多了,或者params单词有没有写错)
11 post-data-字符串格式数据
12 form表单和按钮-默认刷新
一般页面在进行提交表单数据时,会进行跳转,用户无法停留在当前的页面,导致体验很差,这是表单的默认提交行为导致的,所以以后凡是在表单提交事件中的代码中一定要写上event.preventDefault()阻止表单的默认事件
13 快速获取form表单input标签的值
13.1 jq的写法
步骤:
- 要具备form标签
- 然后每一个input标签要有一个name属性--否则用户填写的信息无法被采集到
- 然后要引入jq包
- 最后在表单提交时,写上序列化参数的代码就行了--这里的按钮应该是提交按钮,也就是要给普通的按钮加上type="submit",表示提交按钮,这样该按钮点击时,才会触发表单的默认事件-submit提交事件---而且该按钮标签要放在form标签里面,关联对应的表单,表示提交的是对应的表单的数据(如果不想把按钮放在form标签里,怕破坏原有的html结构,可以按以下这样做,给按钮加一个form="属性值",给form标签加一个id="属性值",这两个属性值要对应,就行了)
但是该方法也有缺点:
13.2 原生js的写法
一定要注意后台接口是否支持formdata
步骤:要具备form标签,然后每一个input标签要有一个name属性
实现的效果跟上述一样
formdata不像一般的对象,它比较害羞,不能通过打印直接查看它的值
13.3 formdata()和serialize()的区别
14 FormData快速获取表单中的值
15 axios发送请求的简写方式
15.1 get请求简写方式
15.2 post请求简写方式
-
其他一些请求类型比如 put delete patch 具体参考文档,如果文档请求参数是query参数,那参数就是写在params里,跟get一样,那么请求的简写方式跟get一样
-
如果文档请求参数是body参数,那参数就是写在data里,跟post一样,那么请求的简写方式跟post一样
16 axios-基地址
17 文件上传
17.1 把图片文件加载到浏览器 显示出来
17.2 将多个图片文件加载到浏览器 显示出来
17.3 把文件发送给服务器
用fd.append()来添加数据
formdata.append(参数键,任意参数值)
这个fd.append()的第一个参数怎么写,具体看接口文档
18 请求报文和响应报文
18.1 请求报文
请求报文规定了客户端以什么格式把数据发送给服务器
请求报文由4 个部分组成
- 请求行(request line)
- 请求头部( header )
- 空行
- 请求体
18.2 响应报文
响应报文规定了服务器以什么格式把数据响应给客户端
响应报文由4 个部分组成
- 状态行
- 响应头部
- 空行
- 响应体
19 状态码
19.1 http 响应状态码
概念:http 响应状态码(Status Code)由三位数字组成,用来标识响应成功与否的状态。
作用:客户端浏览器根据响应状态码,即可判断出这次 http 请求是成功还是失败了。
常见的 http 响应状态码
19.2 业务状态码
业务状态码用来表示这次业务处理的成功与否
19.3 区分响应状态码和业务状态码的不同
- 所处的位置不同
- 表示的结果不同
- 通用性不同
所处的位置
- http状态码可以直接在状态行看见
- 业务状态码只可以在响应体中看见
表示的结果
- http状态码表示这次请求发送给了服务端,不能说明这次的业务操作就是成功!
- 业务状态码表示这次请求业务是否成功!!
通用性
- http状态码全行业通用
- 业务状态码全行业通用(换公司和换项目都不一样)
20 原生的Ajax代码
20.1 原生方式发起get请求不带参数
原生的Ajax请求成功之后返回的是response,axios库请求成功之后返回的是result
20.2 原生方式发起get请求带参数
20.3 原生方式发起post请求
请求体格式 | Content-Type |
---|---|
参数=值&参数=值 | application/x-www-form-urlencoded |
'{ "id": 1, "name": "zs" }' | application/json |
new FormData() | multipart/form-data; xxxxxxxxx随机字符 |
传递的参数为字符串的形式时
传递的参数为JSON字符串的形式时
传递的参数为formData的形式时,不需要设置content-type
21 案例练习-封装原生Ajax功能
实现如下功能:
代码实现功能一:
代码实现功能二:
22 跨域
22.1 跨域和同源的概念
跨域和同源其实是浏览器的一种安全机制,不同源的或者跨域了两个URL之间,默认不让你们做数据交互(不让你发Ajax请求)
跨域的出现是因为浏览器有个同源策略
那么什么叫同源策略呢?
就是两个URL之间要满足三个相同,只要有一个不相同,就会造成跨域
- 协议的名称
- 主机/域名/IP地址
- 端口号
22.2 跨域的解决方案
22.2.1 cors
目前用的比较多的是cors,这是需要后端来解决的,不需要前端解决,如果后端没空,那就前端自己加上以下代码就可以了
const express = require('express');
// const cors = require('cors');
const app = express();
// app.use(cors())
app.get('/books', (req, res) => {
res.send({
code: 0,
message: '查询成功',
data: [{ name: '红楼梦' }, { name: '三国' }],
});
});
app.listen(3456)
但是原理还是 res.header("Access-Control-Allow-Origin", "*"); 这一行 设置响应头。
如果接口的响应头有Access-Control-Allow-Origin,说明后端在写这个接口的时候,允许跨域。
22.2.2 jsonp
前端的页面是 www.baidu.com
后端接口 www.qq.com
1 访问 后端的一个接口 返回一些数据 前端拿到数据 正常做遍历 渲染
1 接口 http://www.itcbc.com:3006/api/getscript
2 前端利用 script 标签不会跨域的特点
3 只能用get请求
<script>
// 想方法 获取数据
// let result = ......
// 希望 show方法 你自己在前端定义
// 服务器帮你把数据 装到 show(数据)
// 什么时候请求完成 后端返回的代码中 自动帮我们调用 show方法
// 在show方法中编写业务即可
function show(option) {
// 就是我们前端自己的业务
// console.log(option);
// const result=option.data.data;
// result.map....
}
</script>
<script src="http://www.itcbc.com:3006/api/getscript2"></script>
23 NProgress
使用NProgress之前的准备工作
下载包,然后引包
注意引入的顺序
在每一次发送Ajax请求的时候使用NProgress
但是如果一个页面的请求接口有很多个的话,每一个接口都要加这两行代码,工作量很大,所以为了方便,我们引进拦截器这个概念
24 拦截器
拦截器有两种:请求拦截器和响应拦截器
拦截器的使用步骤
1 新建一个js文件,在index.html文件引进--注意引进顺序,要在我们写请求接口代码的文件index.js前引进,因为要在发送请求之前就先设置好拦截器
2 像上面一样引进NProgress的两个包,这样才可以使用NProgress.start() , NProgress.done()两段代码
3 在新建的js文件里写上以下这段代码(以后工作要用到拦截器直接拷贝这段代码到项目中)
// 添加一个请求拦截器
axios.interceptors.request.use(function (config) {
//开始请求时开启进度条
NProgress.start() //注意是大写的
return config;
}, function (error) {
//如果一开始请求失败关闭进度条
NProgress.done()
console.log('请求失败');
return Promise.reject(error);
});
// 添加一个响应拦截器
axios.interceptors.response.use(function (response) {
//响应成功关闭进度条
NProgress.done()
console.log("响应成功");
return response;
}, function (error) {
//响应失败关闭进度条
NProgress.done()
console.log('响应失败');
return Promise.reject(error);
});
实现的效果如下:
调接口没完成时,顶部显示进度条和右侧显示loading效果,调完接口返回数据时,就会隐藏顶部进度条和右侧的loading效果
25 fetch()
这是一种新的请求接口数据的方法,类似原生的Ajax,但跟它又有一定的区别
<script>
/*
fetch 类似 XMLHttpRequst 请求和响应
1 新 技术
2 功能 和 XMLHttpRequst 一样
3 用法 简单 fetch
4 axios(用得最多) fetch(其次)
5 axios可以使用拦截器-基地址 ,而fetch不可以使用拦截器和基地址
*/
// 1 get请求
fetch('http://www.itcbc.com:3006/api/getbooks')
.then((result) => {
return result.json(); // 固定搭配 表示 把响应结果转成json 来使用
})
.then(result=>{
console.log(result);
})
// 2 post 请求
// fetch('url', {
// method: 'POST', // 请求类型
// headers: {
// 'Content-Type': 'application/json', // 设置内容
// },
// body: JSON.stringify(data), // post请求的参数部分
// });
</script>
26 防抖和节流
26.1 防抖--关键技术原理--延时器
在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。本质上是通过设置一个延时器
防抖一般用在搜索框业务上,拿之前做的那个图书管理案例来分析:
在搜索框输入我要搜索的值时,这个过程有一个要注意的点:
<script>
/*
1 当我输入完毕了, 你再去发送请求!!
2 如何判断输入完毕
1 如果你输入了文字 过了 2s后,都没有新的输入 我就认为 你输入完毕了
3 延时器
4 过程
1 每一次按下按键
1 清除上一个延时器
2 开启新的延时器
2 例如
1 按下 按键 "A"
2 开启一个延时器 => "A" 发送给后端
3 按下 按键 "AB"
4 先清空上一个 延时器 “A”
5 开启一个延时器 => "AB" 发送给后端
6 按下 按键 "ABC"
7 先清空上一个 延时器 “AB”
8 开启一个延时器 => "ABC" 发送给后端
*/
const input = document.querySelector('input');
let timeId;
input.addEventListener('input', function () {
clearTimeout(timeId);
timeId = setTimeout(function () {
// 正常业务
console.log('发送请求出去');
// 正常业务
}, 2000);
});
</script>
26.2 节流
规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
<button>发送验证码</button>
<script>
/*
1 点击按钮的时候
判断 是否允许执行业务 条件
2 满足条件 允许执行
3 不满足条件 不允许执行
4 延时器时间到了, 重新允许执行
*/
const button = document.querySelector('button');
button.addEventListener('click', function () {
button.disabled = true; // 禁用按钮
// console.log('发送一次验证码');
let times = 3;
let timeId = setInterval(() => {
times--;
console.log(times);
if (times === 0) {
clearInterval(timeId);
button.disabled = false; // 重新启用按钮
}
}, 1000);
});
</script>
26.3 总结
- 函数防抖是某一段时间内只执行一次,而函数节流是间隔时间执行。
27 扩展
1 关闭表单之前填写的默认信息,就是说那些表单的输入框填过一次值之后,在点击输入框时,会有一个下拉菜单,显示之前填过的数据,有时候很烦,这时候只需要给表单加上一个autocomplete="off"就行了(autocomplete="off" 添加在 form标签上, 关闭 form标签中的input标签的历史记录)
2 提交表单后要清空表单所有input框的值--高级做法 获取表单DOM元素为form,然后form.reset()搞定,利用表单的一个reset()方法
3 JSON的语法要求
4 序列化和反序列化
5 restful api
以前发送Ajax请求只有两种类型: get 和 post
restful api : get post delete put patch