服务器
- 服务器的本质:就是一台电脑
- 作用:存放任何网页需要的资源(数据也是资源)
客户端
- 前端开发中,客户端特指“Web 浏览器”
- 作用:将互联网世界中的Web资源加载并呈现到浏览器窗口中供用户使用
URL地址
- 数据也是服务器上的资源
- 对数据的操作(增删改查),也对应着不同的URL地址
客户端与服务器通信的过程
请求-响应(两个步骤)
- 请求:客户端通过网络去找服务器要资源的过程,叫做“请求”
- 响应:服务器把资源通过网络发送给客户端的过程,叫做“响应”
Ajax
- Ajax是浏览器中的技术:用来实现客户端网页请求服务器的数据。
- 一种使用JS来异步获取XML格式数据的技术
- 同步:代码执行马上有结果
- 异步:代码执行不一定马上有结果
请求
请求方式
Ajax请求数据有5种常见方式
- POST——向服务器新增数据
- GET——从服务器获取数据
- DELETE——删除服务器上的数据
- PUT——更新服务器上的数据(侧重于完整更新:更新用户的完整信息)
- PATCH——更新服务器上的数据(侧重于部分更新:更新用户的手机号码)
请求参数
查询数据-params:{}
一条参数
axios({
method:"get",
url:"http://www.itcbc.com:3006/api/getbooks",
params:{
bookname:"万少"
}
}).then(result=>{
const arr=result.data.data
render(arr)
})
多条参数
axios({
method:"get",
url:"http://www.itcbc.com:3006/api/getbooks",
params:{
bookname:"万少",
id:"5946"
}
}).then(result=>{
const arr=result.data.data
render(arr)
})
url拼接参数
一条参数
axios({
method: "get",
// 拼接参数时不需要单双引号
url: "http://www.itcbc.com:3006/api/getbooks?id=5927",
}).then((result) => {
const arr = result.data.data;
render(arr);
});
多条参数
axios({
method: "get",
// 拼接参数时不需要单双引号
url: "http://www.itcbc.com:3006/api/getbooks?id=5927&bookname=窗边的小豆豆",
}).then((result) => {
const arr = result.data.data;
render(arr);
});
根据用户输入查询数据案例
用到的技术
- 参数默认值
- 变量拼接字符串
- 数据驱动视图
<!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>Document</title>
</head>
<body>
<input type="text" id="user-enter" />
<table>
<thead>
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>出版社</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script src="../Ajax-day01/lib/axios.js"></script>
<script>
const tbody = document.querySelector("tbody");
const userEnter = document.querySelector("#user-enter");
getData();
userEnter.addEventListener("keyup", function (e) {
if (e.key === "Enter") {
const value = this.value.trim();
if (value) {
const query=`?bookname=${value}`
getData(query);
this.value = "";
} else {
getData();
}
}
});
// 获取数据单独封装一段代码
// js高级-参数默认值
function getData(query = "") {
axios({
method: "get",
url: `http://www.itcbc.com:3006/api/getbooks` + query,
}).then((result) => {
const arr = result.data.data;
render(arr);
});
}
// 渲染函数也单独封装
function render(arr) {
const arrHtml = arr
.map(
(value) => `
<tr>
<td>${value.id}</td>
<td>${value.bookname}</td>
<td>${value.author}</td>
<td>${value.publisher}</td>
</tr>
`
)
.join("");
tbody.innerHTML = arrHtml;
}
</script>
</body>
</html>
添加数据
data:{}
- 提交方式——
method:"post" url——后端提供(肯定跟获取数据的url不一样)- 传参方法——
data:{}
<body>
<button>新增数据</button>
<script src="../Ajax-day01/lib/axios.js"></script>
<script>
const btn = document.querySelector("button");
btn.addEventListener("click", function () {
axios({
method: "post",
url: "http://www.itcbc.com:3006/api/addbook",
data: {
bookname: "守护甜心",
author: "越前龙马",
publisher: "蜡笔小新",
},
}).then((result) => {
console.log(result);
});
});
// 新增数据 url 请求方式method 参数对象都有所不同
</script>
</body>
用户输入新增数据
<!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>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
flex: 1;
}
table {
display: block;
width: 50%;
}
table tbody tr:nth-child(odd){
background-color: yellow;
}
table,
.user-box {
margin: 50px;
float: left;
}
input {
display: block;
margin: 10px auto;
}
</style>
</head>
<body>
<div class="user-box">
<input type="text" id="bookname" placeholder="书名" />
<input type="text" id="author" placeholder="作者" />
<input type="text" id="publisher" placeholder="出版社" />
<button>添加数据</button>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>出版社</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script src="../Ajax-day01/lib/axios.js"></script>
<script>
const tb=document.querySelector("tbody")
const booknameDom=document.querySelector("#bookname")
const authorDom=document.querySelector("#author")
const publisherDom=document.querySelector("#publisher")
const btn=document.querySelector("button")
// 刷新页面渲染表单
getData()
// 按钮事件注册
btn.addEventListener("click",function () {
const bookname=booknameDom.value
const author=authorDom.value
const publisher=publisherDom.value
// ES6方式设置属性
const data={
bookname,
author,
publisher
}
// 调用新增
addData(data)
})
// 新增数据函数
function addData(data) {
axios({
method:"post",
url:"http://www.itcbc.com:3006/api/addbook",
// es6
data
}).then(result=>{
console.log(result);
getData()
})
}
// 先封装查询函数
function getData() {
axios({
method:"get",
url:"http://www.itcbc.com:3006/api/getbooks"
}).then(result=>{
if(result){
console.log("获取result成功");
const dataArr=result.data.data
render(dataArr)
}
})
}
// 渲染函数
function render(arr) {
const html=arr.map(value=>`
<tr>
<td>${value.id}</td>
<td>${value.bookname}</td>
<td>${value.author}</td>
<td>${value.publisher}</td>
</tr>
`).join("")
tb.innerHTML=html
}
</script>
</body>
</html>
编辑数据
- 点击编辑操作,获取数组下标或者数据id(数据有隐藏的详细信息时用id),将数据传到输入框内
- 用户编辑文本内容
- 点击修改按钮,设置
const data={},将表单内容添加进data - 文档说明id必填,但是用户一般没有对id的需求,所以在第一步的时候就直接获取数组下标,后续设置为原值即可
<body>
<div class="user-box">
<input type="text" id="bookname" placeholder="书名" />
<input type="text" id="author" placeholder="作者" />
<input type="text" id="publisher" placeholder="出版社" />
<button>修改数据</button>
</div>
<table border="1">
<thead>
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>出版社</th>
<th>操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
<!-- 引入axios.js -->
<script src="../Ajax-day01/lib/axios.js"></script>
<script>
const tbody = document.querySelector("tbody");
const booknameDom = document.querySelector("#bookname");
const authorDom = document.querySelector("#author");
const publisherDom = document.querySelector("#publisher");
const btn = document.querySelector("button");
let arr = [];
let id;
// 按钮点击获取表单数据,修改数据
btn.addEventListener("click", function () {
const data = {
id: id,
bookname: booknameDom.value,
author: authorDom.value,
publisher: publisherDom.value,
appkey: "1904050132",
};
put(data);
});
// 修改函数
function put(data) {
axios({
method: "put",
url: "http://www.itcbc.com:3006/api/updatebook",
data,
}).then((result) => {
console.log(result);
// 修改成功,重新渲染表单
getData();
});
}
tbody.addEventListener("click", function (e) {
if (e.target.nodeName === "A") {
const i = e.target.dataset.index;
id = arr[i].id;
console.log(i);
booknameDom.value = arr[i].bookname;
authorDom.value = arr[i].author;
publisherDom.value = arr[i].publisher;
}
});
</script>
</body>
删除数据
- 请求方式——
method:"delete" - 参数方法——
params:{}
confirm()
js内置确认框
- 点击确定返回true
- 点击取消返回false
用户删除数据案例
<!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>Document</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
a {
text-decoration: none;
color: #000;
font-size: 14px;
}
table {
display: block;
text-align: center;
}
table td,
table th {
padding: 5px 10px;
}
table tbody tr:nth-child(odd) {
background-color: yellow;
}
table,
.user-box {
margin: 50px;
float: left;
}
input {
display: block;
margin: 10px auto;
}
</style>
</head>
<body>
<div class="user-box">
<input type="text" id="bookname" placeholder="书名" />
<input type="text" id="author" placeholder="作者" />
<input type="text" id="publisher" placeholder="出版社" />
<button>添加数据</button>
</div>
<table>
<thead>
<tr>
<th>ID</th>
<th>书名</th>
<th>作者</th>
<th>出版社</th>
<th>操作</th>
</tr>
</thead>
<tbody></tbody>
</table>
<script src="../Ajax-day01/lib/axios.js"></script>
<script>
const tb = document.querySelector("tbody");
const booknameDom = document.querySelector("#bookname");
const authorDom = document.querySelector("#author");
const publisherDom = document.querySelector("#publisher");
const btn = document.querySelector("button");
const del = document.querySelector("a");
// 刷新页面渲染表单
getData();
// 按钮事件注册
btn.addEventListener("click", function () {
const bookname = booknameDom.value;
const author = authorDom.value;
const publisher = publisherDom.value;
// ES6方式设置属性
const data = {
bookname,
author,
publisher,
};
// 调用新增
addData(data);
});
// 新增数据函数
function addData(data) {
axios({
method: "post",
url: "http://www.itcbc.com:3006/api/addbook",
// es6
data,
}).then((result) => {
console.log(result);
getData();
});
}
// 先封装查询函数
function getData() {
axios({
method: "get",
url: "http://www.itcbc.com:3006/api/getbooks",
}).then((result) => {
if (result) {
console.log("获取result成功");
const dataArr = result.data.data;
render(dataArr);
}
});
}
// 渲染函数
function render(arr) {
const html = arr
.map(
(value) => `
<tr>
<td>${value.id}</td>
<td>${value.bookname}</td>
<td>${value.author}</td>
<td>${value.publisher}</td>
<td><a data-index="${value.id}" href="javascript:;">删除</a></td>
</tr>
`
)
.join("");
tb.innerHTML = html;
}
// del按钮
tb.addEventListener("click", function (e) {
if (e.target.nodeName === "A") {
// 简写,params需要的是 id:"xxx"
const { id } = e.target.dataset.index;
delData(id);
}
});
// 删除函数
function delData(id) {
axios({
method: "delete",
url: "http://www.itcbc.com:3006/api/delbook",
params: {
// 简写
id,
},
}).then((result) => {
console.log(result);
getData();
});
}
</script>
</body>
</html>
API接口文档
实际开发中出现错误,优先查看文档三个地方
- 接口url
- 请求方式
- 请求参数
network工具
- 浏览器开发者工具中,有一个面板为network,(新版的chrome浏览器是中文版本的“网络”)
form表单
<form>标签最重要的3个属性分别是action,method,enctype- 每个表单域必须包含
name属性,否则用户填写的信息无法被采集到 enctype属性只能搭配post提交方式一起使用;如果是get提交,则enctype没有意义- 注意:
type="submit"表示提交按钮的意思type属性的默认值就是submit,因此type="submit"可以省略不写
获取表单数据
jQuery的serialize()函数
<body>
<form>
<div class="box1">
<label>用户名</label>
<input type="text" name="username" />
</div>
<div class="box2">
<label>密码</label>
<input type="text" name="password" />
</div>
<div class="box3">
<label>其他</label>
<input type="text" />
</div>
<button>提交</button>
</form>
<script src="./lib/jquery.js"></script>
<script>
const btn=document.querySelector("button")
btn.addEventListener("click", function (e){
// 阻止默认行为
e.preventDefault()
const data=$("form").serialize()
console.log(data);
})
</script>
</body>
原生JS实现获取表单数据(常用)
1、formData()对象,快速获取<form>标签里面有name属性的数据,直接打印看不到对象里面的数据(JS内置对象,处理表单数据,new出来使用)
const form=new FormData(document.querySelector("form"))
2、URLSearchParams()对象,把数据转成参数格式(new使用)
const usp=new URLSearchParams()
3、对formData()对象进行forEach()遍历,追加数据到usp对象中待处理
form.forEach((value,key)=>{
usp.append(key,value)
})
4、URLSearchParams()对象内置的toString()方法将数据转换成参数形式
const data=usp.toString()
console.log(data);
5、整套代码可以再省略,URLSearchParams()对象可以直接把formData()对象作为参数传进来
const form=new FormData(document.querySelector("form"))
const usp=new URLSearchParams(form)
console.log(usp.toString());
另外:不使用URLSearchParams()对象,用push()和join()方法来实现一样的效果
const form=new FormData(document.querySelector("form"))
const data=[];
form.forEach((value,key)=>{
data.push(`${key}=${value}`)
})
const str=data.join("&")
console.log(str);
快速获取form数据
- css中,通过
input[name]选择器可以选择到有name属性的标签 .f1 input[name]——获取类名.f1里面具有name属性的表单标签- 利用js
document.querySelectorAll+css选择器获取到所有有name属性的标签,通过遍历forEach(dom=>obj[dom.name] = dom.value)将提前设置好的空对象变为属性值一一对应的对象 - 往后的axios传参直接把
obj丢进去即可
文件上传
限制上传文件类型
accept=""属性
<input type="file" accept="image/*,video/*" />
让用户看到自己选择的图片(修改图片src属性)
<body>
<input type="file" accept="image/*,video/*" />
<img src="" alt="找不到" />
<script src="./lib/axios.js"></script>
<script>
const img = document.querySelector("img");
const input = document.querySelector("input");
input.addEventListener("change", function () {
// this.files 数组形式
console.log(this.files);
const file = this.files[0];
// 用URL对象 找到选择的文件的路径
const src = URL.createObjectURL(file);
img.src = src;
});
</script>
</body>
formData()实现上传
<body>
<input type="file" accept="image/*,video/*" />
<img src="" alt="找不到" />
<script src="./lib/axios.js"></script>
<script>
const img = document.querySelector("img");
const input = document.querySelector("input");
input.addEventListener("change", function () {
// this.files 数组形式
console.log(this.files);
const file = this.files[0];
// 用URL对象 找到选择的文件的路径
const src = URL.createObjectURL(file);
img.src = src;
// 创建空formData对象
const formdata = new FormData();
// 查看文档请求参数 avatar,对象, 将待上传文件加进空formData对象,接口要求
formdata.append("avatar", file);
axios
.post("http://www.itcbc.com:3006/api/formdata", formdata)
.then((result) => {
console.log(result);
});
});
</script>
</body>
报文
- 请求报文规定客户端以什么格式把数据发送给服务器
- 响应报文规定了服务器以什么格式把数据响应给客户端
url参数
- url长度有限制,参数大小不会太大
请求体
- 5种请求方式可以设置请求体
- 请求体大小没有限制,可以提交大量的数据
- 常用请求体格式
- 参数-值(字符串)
- "{'id': 1}"(JSON格式)
- new formData() (FormData对象)
http响应状态码
- 2xx:成功
- 3xx:重定向
- 4xx:客户端错误
- 5xx:服务器错误
http响应状态码,业务状态码区别:
- 表示的结果不同
- 响应状态码只能表示这次请求的成功与否
- 业务状态码表示业务处理成功与否
- 通用性不同
- 响应状态码是由http协议规定,具有通用性
- 业务状态码是后端程序员自定义,不具有通用性
原生Ajax
XMLHttpRequest()
浏览器内置的构造函数
作用:基于实例,发起Ajax请求
发起请求步骤(面试)
-
创建
const xhr=new XMLHttpRequest()对象const xhr=new XMLHttpRequest() -
调用
xhr.open()函数xhr.open("get","http://www.itcbc.com:3006/api/getbooks") -
调用
xhr.send()函数xhr.send() -
监听
load事件xhr.addEventListener("load",function () { console.log(this.response); const obj=JSON.parse(this.response) console.log(obj); })
请求参数
-
拼接到url地址
xhr.open("get","http://www.itcbc.com:3006/api/getbooks?appkey=1904050132") -
传入send()方法
xhr.send(data)
重点理解Ajax发送请求底层封装
-
判断传入的请求方式(
get,post) -
为
get,继续判断data类型- 对象要转成参数格式进行拼接
- 已经是字符串就直接拼接
url
-
为
post,继续判断data是String,Object中的哪一种类型- 是字符类型则直接使用
xhr.send(data) - 是对象,则继续判断是不是属于(
instanceof)FormData()实例,是则xhr.send(data) - 否则先用
data=JSON.Stringify(data)转成字符串,接着xhr.send(data)
<body> <input type="file" accept="image/*" /> <script> // data为继承于FormData()对象 const input = document.querySelector("input"); input.addEventListener("change", function () { const file = this.files[0]; const data = new FormData().append("avatar", file); const option1 = { url: "http://www.itcbc.com:3006/api/formdata", type: "post", data, success(result) { console.log(result); }, }; ajax(option1); }); //__________________________________ // data为字符串 const option1 = { url: "http://www.itcbc.com:3006/api/formdata", type: "post", /* data: { bookname: "wuchengen", author: "tjm", publisher: "xinhuazidian", appkey: "1904050132", }, */ data:"bookname=守护甜心&author=越前龙马&publisher=蜡笔小新", success(result) { console.log(result); }, }; ajax(option1); // data为object普通对象 const option1 = { url: "http://www.itcbc.com:3006/api/formdata", type: "post", /* data: { bookname: "wuchengen", author: "tjm", publisher: "xinhuazidian", appkey: "1904050132", }, */ data:"bookname=守护甜心&author=越前龙马&publisher=蜡笔小新", success(result) { console.log(result); }, }; ajax(option1); // ajax底层封装 function ajax({ url, type, data = "", success }) { const xhr = new XMLHttpRequest(); // GET 请求方式 if (type === "get") { // 继续判断data类型,为对象则转成参数格式再进行拼接 if (typeof data === "object") { data = new URLSearchParams(data).toString(); } xhr.open(type, url + "?" + data); xhr.send(); // POST 请求方式 } else if (type === "post") { xhr.open(type, url); if (typeof data === "string") { xhr.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" ); xhr.send(data); } else if (typeof data === "object") { if (data instanceof FormData) { xhr.send(data); } else { data = new URLSearchParams(data).toString(); xhr.setRequestHeader("Content-type", "application/json"); xhr.send(data); } } } xhr.addEventListener("load", function () { const obj = JSON.parse(this.response); success(obj); }); } </script> </body> - 是字符类型则直接使用
防抖和节流
防止用户在搜索框或其他地方连续不断发送请求浪费性能
防抖
// 防抖延时器
let timeid;
userEnter.addEventListener("input", function (e) {
// 一直输入就一直清除延时器,直到停止输入
clearTimeout(timeid);
timeid = setTimeout(() => {
const value = this.value.trim();
if (value) {
const query = `?bookname=${value}`;
getData(query);
// this.value = "";
} else {
// 获取数据
getData();
}
}, 2000);
});
节流
btn.addEventListener("click", () => {
// 点击结束,立即禁用按钮
btn.disabled = true;
getData();
});
// 获取数据单独封装一段代码
// js高级-参数默认值
function getData(query = "") {
axios({
method: "get",
url: `http://www.itcbc.com:3006/api/getbooks` + query,
}).then((result) => {
const arr = result.data.data;
render(arr);
// 获取到响应数据,开启按钮
btn.disabled = false;
});
}
同源策略&跨域
同源:2个URL地址具有相同协议、主机名、端口号
同源策略
- 浏览器提供的一个安全功能
- 规定:不允许非同源的URL之间进行资源的交互
跨域
- 跨越不同源地址-跨域
- 浏览器允许发起跨域请求,但跨域响应的数据会被浏览器拦截,无法被页面获取到
- 突破跨域限制(2种方案)
- JSONP(非官方):较早,兼容好,仅支持GET请求
- CORS(W3C官方标准):较晚,支持常见请求方式,不兼容低版本浏览器,也是解决跨域数据请求的终极方案
CORS
需要浏览器和服务器同时支持
JSONP
可以把非同源的JavaScript代码请求到本地,并执行
如果请求回来的JS代码只包含函数的调用,则需要程序员手动定义show方法
Git(了解)
版本管理系统
- 作用
- 记录每次代码的变更,以便将来查阅特定版本的修改情况
- 完成多人协作(必须配合远程仓库)
- 管理软件的分类
- 集中式(SVN)
- 分布式(Git)
- 集中式
- 代码版本集中到一个服务器
- 没有网络或者崩溃,无法进行版本管理
- 分布式
- 代码版本分布到每个计算机上
- 99%的操作都是在自己的计算机上完成
- 联网即可同步代码
三个区域
- git内部实现,离不开维护的三个区域
- 工作区(代码区)
- 暂存区
- 仓库
分支
- git分支系统强大
- 分支相当于项目副本
- 初始化后,git默认创建一个master主分支
- 实际开发中,企业不允许在主分支开发,会在分支上开发,最后将代码合并
冲突
-
工作常见场景,合并同名文件时而发生
-
vscode合并冲突时会把冲突内容高亮显示
本地推送到远程仓库
-
码云地址新建远程仓库
-
在需要新建本地仓库的位置右键打开git终端
-
将远程仓库克隆到本地(将会弹出用户名密码输入框)
git clone https://gitee.com/icarrot/rro.git -
在本地仓库里面打开终端,新建一些文件
touch index.js index.html index.css -
文件添加进暂存区
git add . -
暂存区提交到本地仓库
git commit -m "提交说明" -
本地推送到远程仓库
git push
拓展
-
axios的post请求参数可以用字符串data:"bookname=守护甜心&author=越前龙马&publisher=蜡笔小新" -
axios请求方法可以简写(详细查看线上文档)axios.get() axios.post() axios.delete() axios.put() -
拦截器(axios官方文档)——请求前拦截一下显示加载中效果,后端返回数据停止显示加载效果
// 添加请求拦截器 axios.interceptors.request.use( function (config) { // 在发送请求之前做些什么 img.style.display="block" return config; }, function (error) { // 对请求错误做些什么 return Promise.reject(error); } ); // 添加响应拦截器 axios.interceptors.response.use( function (response) { // 2xx 范围内的状态码都会触发该函数。 // 对响应数据做点什么 img.style.display="none" return response; }, function (error) { // 超出 2xx 范围的状态码都会触发该函数。 // 对响应错误做点什么 return Promise.reject(error); } ); -
谷歌浏览器网络调试工具提供了网速调节功能,可以调试需要慢慢加载的代码
-
免费API网站:聚合数据……