一、json 基础
1. JSON 是什么
- JSON: JavaScript Object Notation(JS 对象表示法)
- JSON 独立于任何编程语言, 几乎所有编程语言都提供了访问 JSON 数据的 API 接口
- JSON 是一种语法,用来序列化其它语言创建的数据类型
- JSON 仅支持 6 种数据类型:对象,数组,数值,字符串,布尔值,null
- JSON 只是借用了 JS 中的一些数据表示语法,与 JS 并无关系
2. JSON 数据类型
| 序号 | 类型 | 描述 |
|---|---|---|
| 1 | 简单值 | 数值,字符串,布尔,null |
| 1 | 复合值 | 对象,数组 |
注意: 不支持
undefined(因为除 JS 外,其它语言中没有这个东西)
3. JS 解析 JSON 的 API
| 序号 | 方法 | 描述 |
|---|---|---|
| 1 | JSON.stringify() | 将 JS 对象,序列化为 JSON 字符串 |
| 2 | JSON.parse() | 将 JSON 字符串,解析为 JS 对象 |
3.1 JSON.stringify(data)
// JSON.stringify(data); js -> json
console.log(JSON.stringify(3.14), typeof JSON.stringify(3.14));
console.log(JSON.stringify("php.cn"), typeof JSON.stringify("php.cn"));
console.log(JSON.stringify(true), typeof JSON.stringify(true));
console.log(JSON.stringify(null), typeof JSON.stringify(null));
// json其实就是一个字符串,具有特殊格式的字符串文本,类似html
// 通常对象和数组转为json才有意义
console.log(JSON.stringify({ x: "a", y: "b" }));
console.log(
JSON.stringify([
{ id: 1, name: "admin" },
{ id: 2, name: "php" },
])
);
console.log(JSON.stringify({ a: 1, b: 2, c: 3 }));
// 第二个参数数组进行结果过滤
console.log(JSON.stringify({ a: 1, b: 2, c: 3 }, ["a", "b"]));
// 第二个参数传一下回调
console.log(
JSON.stringify({ a: 1, b: 2, c: 3 }, (k, v) => {
if (v < 2) return undefined;
return v;
})
);
// 第三个参数可以用来格式式输出json字符串的输出
console.log(JSON.stringify({ a: 1, b: 2, c: 3 }, null, 2));
console.log(JSON.stringify({ a: 1, b: 2, c: 3 }, null, "---"));
3.2 JSON.parse()
// JSON.parse(): json -> js对象
let jsObj = JSON.parse(`{"a": 1,"b": 2,"c": 3}`);
console.log(jsObj instanceof Object);
console.log(jsObj.a, jsObj.b, jsObj.c);
二、Ajax 异步请求
特别提示: 异步请求不要使用
live server插件,必须创建一个本地服务器环境
1. 同步与异步
以前端请求,后端响应为例
- 同步: 前端发请求, 必须等到后端响应完成,才允许发送另一个请求
- 异步: 前端发请求后不等待后端响应结果继续执行,后端响应完成通过事件通知前端处理
2. XMLHttpRequest 对象
XMLHttpRequest是浏览器对象,而非 JS 内置对象
2.1 xhr 请求步骤
- 创建 xhr 对象:
const xhr = new XMLHttpRequest() - 配置 xhr 参数:
xhr.open(type, url) - 处理 xhr 响应:
xhr.onload = (...) => {...} - 发送 xhr 请求:
xhr.send(...)
2.2. xhr 对象常用属性
| 序号 | 方法 | 描述 |
|---|---|---|
| 1 | responseType | 设置响应类型 |
| 2 | response | 响应正文 |
2.3 xhr 对象常用方法
| 序号 | 方法 | 描述 |
|---|---|---|
| 1 | open(type,url) | 配置请求参数 |
| 2 | send(data/null) | 发送请求 |
2.4. xhr 对象常用事件
| 序号 | 事件 | 描述 |
|---|---|---|
| 1 | load() | 请求成功 |
| 2 | error() | 请求失败 |
developer.mozilla.org/zh-CN/docs/…
3. FormData 对象
FormData是表单数据构造器
| 序号 | 方法 | 描述 |
|---|---|---|
| 1 | append(name,value) | 请求成功 |
| 2 | delete(name) | 请求失败 |
developer.mozilla.org/zh-CN/docs/…
4. get / post 区别
- get 是 url 传参,post 是
request body请求体传参 - get 回退无影响, post 回退会重复提交
- get 生成的 url 可做书签,post 不可以
- get 只能对 url 进行编码, post 支持多种编码
- get 请求参数会保留在历史记录中, post 参数不保留
- get 参数长度受限,post 无限制
- get 只接受 ascii 码字符,post 无限制
- get,post 底层实现是一致的,都是基于 http 协议
- get 也可以带上 request body, post 也可以带上 url 参数
- get 产生一个 tcp 数据包,post 产生二个 tcp 数据包
- get 产生一个请求, post 产生二个请求
- get 请求,浏览器将 header,data 一起发出,服务器响应 200 成功
- post 请求,浏览器先发出 header,得到响应 100 continue,再发出 data,得到响应 200
- 并非所有浏览器的 post 都产生二次 http 请求,firefox 就只产生一次
5. 跨域
- CORS: 跨域资源共享
- 跨域请求可以是 get,也可以是 post,只不过 get 居多
- cors-post 时,需要在服务器端进行头部设置
- jsonp 只能是 get
三、ajax-get 请求
<button>Ajax-GET请求</button>
<p></p>
<script>
const btn = document.querySelector("button");
btn.onclick = () => {
// 1. 创建 xhr 对象:
const xhr = new XMLHttpRequest();
// 2. 配置 xhr 参数:
xhr.open("get", "test1.php?id=2");
xhr.responseType = "json";
// 3. 处理 xhr 响应:
xhr.onload = () => {
// xhr.response: 响应的返回值,是json字符串
// console.log(typeof xhr.response);
// 如果显式的设置了响应类型,如json,这里就是直接自动转为js对象
console.log(xhr.response);
// 是将json转为js对象
// console.log(JSON.parse(xhr.response));
let user = `${xhr.response.name} ( ${xhr.response.email} )`;
document.querySelector("p").textContent = user;
};
xhr.onerror = () => console.log("Error");
// 4. 发送 xhr 请求: xhr.send(...)
xhr.send(null);
};
</script>
四、ajax-post 请求
html 页面文件:
<style>
body {
background-color: lightcyan;
}
.login {
width: 20em;
/*border: 1px solid;*/
box-shadow: 0 0 8px #888;
padding: 0 1em 1em;
background-color: lightseagreen;
color: white;
margin: 2em auto;
display: grid;
place-items: center;
}
.login form {
display: grid;
grid-template-columns: 3em 1fr;
gap: 1em 0;
}
.login form input {
border: none;
outline: none;
}
.login form input:focus,
.login form input:hover {
box-shadow: 0 0 5px lime;
}
.login form button {
background-color: lightsalmon;
color: white;
outline: none;
border: none;
height: 2em;
}
.login form button:hover {
background-color: salmon;
cursor: pointer;
box-shadow: 0 0 5px lime;
}
/* 按钮与提示信息显示在第二列 */
.login form button,
.tips {
grid-area: auto / 2;
}
</style>
<div class="login">
<p>用户登录</p>
<form action="" onsubmit="return false">
<label for="email">邮箱:</label>
<input type="email" name="email" id="email" placeholder="demo@email.com" />
<label for="password">密码:</label>
<input type="password" name="password" id="password" placeholder="不少于6位" />
<button>提交</button>
<span class="tips"></span>
</form>
</div>
js 文件实现:
const form = document.querySelector(".login form");
const btn = document.querySelector(".login button");
const tips = document.querySelector(".tips");
// FormData: 表单数据的序列化
// let data = new FormData(form);
// data.append("email", form.email.value);
// console.log(data.get("email"), data.get("password"));
// console.log(data);
btn.onclick = ev => {
// 禁止默认的提交行为
ev.preventDefault();
// 1. 创建 xhr 对象:
const xhr = new XMLHttpRequest();
// 2. 配置 xhr 参数:
xhr.open("post", "test2.php");
// 3. 处理 xhr 响应:
xhr.onload = () => {
tips.textContent = xhr.response;
};
xhr.onerror = () => console.log("Error");
// 4. 发送 xhr 请求
xhr.send(new FormData(form));
};
五、ajax-get-cors 请求
// cors: 跨域资源共享
// 同源策略: 为请求的安全,浏览器禁止通过脚本发起一个跨域的请求
// 只允许通过脚本发起基于同源的请求
// 同源指: 协议相同,域名/主机名相同,端口相同
// http://www.abc.com http
// https://www.abc.com https
// 协议不同
// https://www.a.com
// https://www.b.com
// 主机不同
// https://a.cn:8080
// https://a.cn:9090
// 端口不同
<button>跨域请求CORS</button>
<script>
const btn = document.querySelector("button");
btn.onclick = (ev) => {
// 1. xhr对象
const xhr = new XMLHttpRequest();
// 2. 配置xhr, 跨域请求
xhr.open("get", "http://world.io/cors1.php");
// 3. 处理xhr响应
xhr.onload = () => console.log(xhr.response);
// 4. 发送xhr请求
xhr.send(null);
};
</script>
六、ajax-post-cors 请求
<button>跨域请求CORS-POST</button>
<p class="tips"></p>
<script>
const btn = document.querySelector("button");
const tips = document.querySelector(".tips");
btn.onclick = (ev) => {
// 1. xhr对象
const xhr = new XMLHttpRequest();
// 2. 配置xhr, 跨域请求
xhr.open("post", "http://world.io/cors2.php");
// 3. 处理xhr响应
xhr.onload = () => (tips.innerHTML = xhr.response);
// 4. 发送xhr请求
// 模拟表单数据: FormData
let formData = new FormData();
formData.append("email", "admin@qq.com");
formData.append("password", "123456");
xhr.send(formData);
};
</script>
七、案例:选项卡
html 文件:
<div class="tabs">
<!-- 导航 -->
<ul class="tab">
<li class="active" data-index="1">省内</li>
<li data-index="2">国内</li>
<li data-index="3">国际</li>
</ul>
<!-- 与导航标签页对应的详情列表 -->
<ul data-index="1" class="item active">
<li><a href="">新华社曝安徽亳州麦田“长”出</a></li>
<li><a href="">新华社曝安徽亳州麦田“长”出</a></li>
<li><a href="">新华社曝安徽亳州麦田“长”出</a></li>
<li><a href="">新华社曝安徽亳州麦田“长”出</a></li>
</ul>
<ul data-index="2" class="item">
<li><a href="">武汉机场跨境电商进出口猛</a></li>
<li><a href="">武汉机场跨境电商进出口猛</a></li>
<li><a href="">武汉机场跨境电商进出口猛</a></li>
<li><a href="">武汉机场跨境电商进出口猛增</a></li>
</ul>
<ul data-index="3" class="item">
<li><a href="">大湾区国际信息科技协会在港成立 </a></li>
<li><a href="">大湾区国际信息科技协会在港成立 </a></li>
<li><a href="">大湾区国际信息科技协会在港成立 </a></li>
<li><a href="">大湾区国际信息科技协会在港成立 </a></li>
</ul>
</div>
css 文件:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
a {
text-decoration: none;
color: #555;
}
a:hover {
text-decoration: underline;
color: red;
}
li {
list-style: none;
line-height: 1.6em;
}
li:hover {
cursor: default;
}
.tabs {
width: 300px;
height: 300px;
margin: 30px;
background-color: #e6e6e6;
display: flex;
flex-direction: column;
}
.tab {
height: 36px;
display: flex;
}
.tab li {
flex: auto;
text-align: center;
line-height: 36px;
background-color: #fff;
}
.tab li.active {
background-color: #e6e6e6;
}
.tab li:hover {
cursor: pointer;
}
/* 默认所有选项卡只有一个显示,其它隐藏 */
.item {
padding: 20px;
display: none;
}
.item.active {
display: block;
}
js 文件:
// 事件代理实现导航的切换
const tab = document.querySelector(".tab");
const items = document.querySelectorAll(".item");
tab.onclick = ev => {
// console.log(ev.currentTarget);
// console.log(ev.target);
// 1. 清空之前的激活样式,并将当前导航设置为激活状态
[...tab.children].forEach(item => item.classList.remove("active"));
ev.target.classList.add("active");
// 2. 根据data-index来确定应该将哪个列表进行激活并显示出来
items.forEach(item => item.classList.remove("active"));
// console.log([...items].filter((item) => item.dataset.index === ev.target.dataset.index).pop());
[...items]
.filter(item => item.dataset.index === ev.target.dataset.index)
.pop()
.classList.add("active");
};
八、案例:一键换肤
html 文件:
<div class="container">
<img src="./images/1.jpg" alt="" />
<img src="./images/2.jpg" alt="" />
<img src="./images/3.jpg" alt="" />
</div>
css 文件:
.container {
width: 300px;
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 10px;
}
.container > img {
width: 100%;
border: 3px solid #fff;
opacity: 0.6;
}
.container > img:active {
opacity: 1;
}
.container > img:hover {
opacity: 1;
cursor: pointer;
width: 105%;
}
body {
background-image: url("./images/1.jpg");
background-size: cover;
background-repeat: no-repeat;
}
js 文件:
// 事件代理
const box = document.querySelector(".container");
box.onclick = function (ev) {
// body
const body = document.body;
// 新的背景图片
let imgUrl = `url('${ev.target.src}')`;
body.style.backgroundImage = imgUrl;
};
// 使用箭头函数来简化
// document.querySelector(".container").onclick = (ev) =>
// (document.body.style.backgroundImage = `url('${ev.target.src}')`);