Ajax
基础概念
服务器
服务器: 一台存储网站内容、网站文件的电脑
资源
资源:
1… 网站中使用的文件(html、css、图片、…)这些东西就叫做资源
2… 数据也是服务器上的资源,而且是一个网站的灵魂
客户端
客户端:
1… 客户端应该指上网的设备
2… 但是在前端开发中,可以把浏览器理解为客户端即可。
URL
url: 对服务器上的数据,进行查询、新增、修改、删除等操作,都需要URL
请求和响应
请求
1… 客户端 向服务器 要资源的 过程
2… 客户端 向服务器 提交资源的过程
…
3… 通过 url 地址,连接到服务器,广义上讲都叫做请求
请求是由谁发送的
客户(客户端)
什么是响应
响应: 客户端发送了请求,服务器做出的回应,叫做响应
响应是谁做出的
服务器
5种常用的请求方式
1… 获取服务器上的数据,需要使用 GET 方式
2… 新增(添加)数据,需要使用 POST 方式
3… 删除数据,需要使用 DELETE 方式
4… 完整修改(更新)数据,需要使用 PUT 方式
5… 修改(更新)部分数据,需要使用 PATCH 方式
了解到Ajax的作用
Axios库介绍
官方网站:https://www.npmjs.com/package/axios
中文网站1:https://www.axios-http.cn/
中文网站2:http://www.axios-js.com/zh-cn/docs/
使用之前,需要下载。
接口及接口文档
发送请求的时候,用什么地址?请求方式是什么?该提交哪些参数?这个请求是干什么的?
● 接口就是请求的那个地址,大家称它为 数据接口,简称接口
● 接口是后端同学设计的
● 后端同学需要出具一个接口的使用说明书,也就是接口文档
● 前端同学,要会看接口文档,会根据接口文档发送请求
●接口文档描述的是query参数或查询参数,代码要用params
●接口文档描述的是body参数或请求体,代码要用data
Ajax课上使用的接口文档:https://docs.apipost.cn/preview/f62dc0b91dc8d8ea/c31d9a50dccf65e3
加入appkey区分数据
获取图书的时候,带 params 配置:
代码如下(示例):
axios({
method: "GET",
url: "http://www.itcbc.com:3006/api/getbooks",
params: {
appkey: "zzzcccsss",
},
}).then((result) => {
添加图书的时候:带data配置:
代码如下(示例):
axios({
method: "POST",
url: "http://www.itcbc.com:3006/api/addbook",
data: { bookname, author, publisher, appkey: "zzzcccsss" },
}).then((result) => {
语法练习
GET请求
axios({请求的配置}).then(result=>{result.data就是响应的结果})
代码如下(示例):
<body>
<!-- 引入axios.js -->
<script src="./lib/axios.js"></script>
<script>
// axios({请求的配置}).then(result=>{result.data就是响应的结果})
axios({
//键:值,
//键:值,
method: "GET", //指定请求方式;GET不区分大小写,建议大写
url: "http://www.itcbc.com:3006/api/getbooks",
}).then((result) => {
console.log(result.data); //result.data是服务器响应的真正结果
});
</script>
</body>
带条件的GET请求
带条件的查询,另一个说法是 带查询参数
在请求的配置项中,加 params配置即可。
代码如下(示例):
<body>
<script src="./lib/axios.js"></script>
<script>
axios({
method: "GET",
url: "http://www.itcbc.com:3006/api/getbooks",
// 加筛选条件(查询参数)
params: {
// id: 38258,
bookname: "斗破苍穹",
},
}).then((result) => {
console.log(result.data);
});
</script>
</body>
POST请求
接口文档描述的是query参数或查询参数,代码要用params
接口文档描述的是body参数或请求体,代码要用data
代码如下(示例):
<body>
<button>发送请求,添加图书</button>
<script src="./lib/axios.js"></script>
<script>
// 点击按钮,添加图书
document.querySelector("button").addEventListener("click", function () {
// 按照接口文档说明,发送请求,添加图书
axios({
method: "POST",
url: "http://www.itcbc.com:3006/api/addbook",
//接口文档描述的是query参数或查询参数,代码要用params
//接口文档描述的是body参数或请求体,代码要用data
data: {
bookname: "斗破苍穹134", //需求文档有填写内容要求
author: "土豆",
publisher: "仙侠出版社",
},
}).then((result) => {
console.log(result.data);
});
});
</script>
</body>
DELETE请求
代码如下(示例):
<body>
<button>点击删除</button>
<script src="./lib/axios.js"></script>
<script>
document.querySelector('button').addEventListener('click', function () {
// 按照axios的语法,把代码的雏形写好
axios({
method: 'DELETE',
url: 'http://www.itcbc.com:3006/api/delbook',
// 接口文档让提交 query参数,所以代码中写 params
params: {
id: 2213
}
}).then(result => {
console.log(result.data)
})
})
</script>
</body>
Network - 网络面板
面板介绍
隐藏时间轴(可选)
禁用浏览器缓存
模拟网速(看看就行,不要乱调)
No throttling – 不限速
Fast 3G – 模拟快速3G网络
Slow 3G – 模拟慢速3G网络
显示请求方式
查看请求状态
200 表示成功
pending 表示等待(可能网络不好或者断网了)
4xx 和 5xx 都表示不同程度的错误
Failed 表示失败
查看提交的数据(非常重要)
查看响应结果(非常重要)
总结
数据回填
所以的修改,都需要数据回填。
数据回填,也叫做数据回显。就是把修改的这条数据放回到 输入框 中。
1… 具体做法一:循环遍历的时候,用 编辑 按钮的 data-xxx 属性,将数据存储起来:
代码如下:
let str = data.data.map((item) => {
return `
<tr>
<th scope="row">${item.id}</th>
<td>${item.bookname}</td>
<td>${item.author}</td>
<td>${item.publisher}</td>
<td>
<button data-id="${item.id}" type="button" class="btn btn-link btn-sm btn-delete">删除</button>
<button data-id="${item.id}" data-bookname="${item.bookname}" data-author="${item.author}" data-publisher="${item.publisher}"type="button" class="btn btn-link btn-sm btn-update">编辑</button>
</td>
</tr>
`;
});
点击编辑的时候,获取这些data-xxx属性值,设置给输入框即可:
代码如下:
// 编辑
if (ev.target.classList.contains("btn-update")) {
editModal.show();
// 获取4个data的值
let add = ev.target.dataset;
// 设置输入框的默认值
document.querySelector("#editForm [name=id]").value = add.id;
document.querySelector("#editForm [name=author]").value = add.author;
document.querySelector("#editForm [name=bookname").value = add.bookname;
document.querySelector("#editForm [name=publisher]").value = add.publisher;
}
});
回顾表单元素
注意事项:
表单各项,必须有name属性(和后续的数据提交有关系)
单项按钮组,多个按钮,name属性要一致,才叫做一组
单项按钮、复选按钮,都要设置value值,提交数据的时候,提交的是value值
下拉框,name属性要给 select标签;value属性要给 option标签
代码如下(示例):
<form action="">
单行文本框:
<input type="text" name="username" /><br />
密码框:
<input type="password" name="pwd" /><br />
单项按钮组:
<input type="radio" value="nan" name="sex" />男
<input type="radio" value="nv" name="sex" />女<br />
复选按钮组:
<input type="checkbox" name="hobby" value="cf" />吃饭
<input type="checkbox" name="hobby" value="sj" />睡觉
<input type="checkbox" name="hobby" value="ddd" />打豆豆<br />
下拉框:
<select name="address">
<option value="bj">北京</option>
<option value="sh">上海</option>
<option value="gz">广州</option></select
><br />
文件选择框:
<input type="file" /><br />
多行文本框:
<textarea name="intro" cols="30" rows="3"></textarea><br />
隐藏域:
<input type="hidden" name="id" value="100" /><br />
<!-- h5新增:
<input type="color"> -->
<!-- 表单中的按钮 -->
<!-- 1.提交按钮(点击之后会造成表单提交) -->
<button id="tijiao">提交按钮1</button>
<button type="submit">提交按钮2</button>
<input type="submit" value="提交按钮3" />
<hr />
<!-- 2.普通按钮(点击之后不会有任何反应) -->
<button type="button">普通按钮1</button>
<input type="button" value="普通按钮2" />
<hr />
<!-- 3.重置按钮(点击之后,会重置表单) -->
<button type="reset">重置按钮1</button>
<input type="reset" value="重置按钮2" />
</form>
阻止表单提交行为
方案有两个:
在以后提交数据的时候,可以找到提交按钮,注册click事件;
也可以找到form,注册submit事件。最终的效果是一样的。
// 1. ------------- 点击提交按钮 阻止默认行为----------------------------------------
// document.querySelector('.tijiao').addEventListener('click', function (e) {
// e.preventDefault()
// })
// 2. --------------- 阻止表单提交行为 ----------------------------
document.querySelector("form").addEventListener("submit", function (e) {
e.preventDefault();
axios全局配置
官方参考:https://www.axios-http.cn/docs/config_defaults
全局配置了请求根路径,后面所有的请求,都不需要加请求根路径了
// 全局配置请求根路径
axios.defaults.baseURL = "http://www.itcbc.com:3006";
// 全局配置了请求根路径,后面所有的请求,都不需要加请求根路径了
axios({
method: "GET",
url: "/api/getbooks", //开头的斜线不能丢
}).then((result) => {
console.log(result.data);
});
axios请求方法的别名(简写)
1… GET 和 DELETE
// ---------------------------- GET 和 DELETE -----------------------------------
// 发送GET请求|发送DELETE请求 axios.get(url, { /*请求的配置*/ }).then(result => {})
axios.get("/api/getbooks", { params: { appkey: "zcszcs" } }).then((result) => console.log(result.data));
2… POST 和 PUT 和 PATCH
// ---------------------------- POST 和 PUT 和 PATCH -----------------------------------
// 语法 axios.post(url, data, {/*请求的配置*/})
axios
.post("/api/addbook", {
bookname: "dddd",
author: "dsds",
publisher: "sdfsf",
appkey: "laot334ang",
})
.then((result) => {
console.log(result.data);
});
请求拦截器和响应拦截器
<body>
<script src="./axios.js"></script>
<script>
// 全局配置
axios.defaults.baseURL = 'http://www.itcbc.com:3006'
// 添加请求拦截器
axios.interceptors.request.use(
function (config) {
// 在发送请求之前做些什么(可以在这里做一个请求的配置)
// console.log(config.url)
// config.url = '/api/abcd'
return config;
},
function (error) {
// 对请求错误做些什么(一般情况都不用,请求发不出去,才会执行这个函数)
return Promise.reject(error);
}
);
// 添加响应拦截器
axios.interceptors.response.use(
function (response) {
// 2xx 范围内的状态码都会触发该函数。
// console.log('状态码在 2xx 的范围内')
alert(response.data.message)
// 对响应数据做点什么
return response;
},
function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// console.log('状态码超过了 2xx')
// error.response ==== result
alert(error.response.data.message)
// 对响应错误做点什么
return Promise.reject(error);
}
);
// 发送请求,测试一下
axios.get('/api/getbooks', { params: { appkey: 'laot334ang' } }).then(result => {
console.log(result.data)
})
</script>
</body>
总结
FormData
基本使用
FormData 是一个浏览器内置对象。作用是用于获取表单数据。
● 表单各项必须有 name 属性
● let fd = new FormData(表单) // 可以把表单中的数据收集到了
● ajax提交的时候,直接提交 fd 即可
<body>
<form action="">
用户名:<input type="text" name="username"><br />
密 码:<input type="password" name="pwd"><br />
性 别:<input type="radio" value="男" name="sex">男 <input type="radio" value="女" name="sex">女<br />
<button>提交</button>
</form>
<script src="./lib/axios.js"></script>
<script>
axios.defaults.baseURL = 'http://www.itcbc.com:3006'
// 点击按钮,会造成表单提交,阻止默认行为,使用 FormData 收集表单数据,Ajax提交数据
document.querySelector('button').addEventListener('click', function (e) {
e.preventDefault() // 阻止默认行为
// let fd = new FormData(表单)
let fd = new FormData(document.querySelector('form'))
// ajax提交数据,也就是提交 fd
axios.post('/api/formdata', fd).then(result => {
console.log(result.data)
})
})
</script>
</body>
FormData相关的API
● fd.append(‘键’, 值) — 向原有数据中,新增一个值
● fd.delete(‘键’) — 从原有数据中,移除一个值
● fd.set(‘键’, 值) — 修改原有数据中的一个值
● fd.forEach((value, key) => {}) — 变量查看对象中有哪些数据
axios.defaults.baseURL = 'http://www.itcbc.com:3006'
// 点击按钮,会造成表单提交,阻止默认行为,使用 FormData 收集表单数据,Ajax提交数据
document.querySelector('button').addEventListener('click', function (e) {
e.preventDefault() // 阻止默认行为
// let fd = new FormData(表单)
let fd = new FormData(document.querySelector('form'))
+ // 1. 向原有数据中,新增一个值
+ fd.append('phone', 1322323232)
+ // 2. 从原有数据中,删除一个值
+ fd.delete('pwd')
+ // 3. 修改一个值
+ fd.set('sex', '妖')
+ // 4. 提交前,查看有哪些数据
+ fd.forEach((value, key) => {
+ console.log(key, value)
+ })
// ajax提交数据,也就是提交 fd
axios.post('/api/formdata', fd).then(result => {
console.log(result.data)
})
})
上传文件
原理和提交其他文本值一样,只不过上传,提交的是一个文件而已。
注意,文件选择框,name 必须是 avatar,因为接口要求的。
<body>
<form action="">
用户名:<input type="text" name="username"><br />
密 码:<input type="password" name="pwd"><br />
性 别:<input type="radio" value="男" name="sex">男 <input type="radio" value="女" name="sex">女<br />
头 像:<input type="file" name="avatar"><br />
<button>提交</button>
</form>
<script src="./axios.js"></script>
<script>
axios.defaults.baseURL = 'http://www.itcbc.com:3006'
document.querySelector('button').addEventListener('click', function (e) {
e.preventDefault()
// 收集表单中的数据
let fd = new FormData(document.querySelector('form'))
// 提交数据(数据中包括文件,提交数据,就相当于上传文件)
axios.post('/api/formdata', fd).then(result => {
console.log(result.data)
})
})
</script>
</body>
没有form标签的情况下,如何实现文件上传:
<body>
<input type="file" name="" id="" />
<script src="./lib/axios.js"></script>
<script>
document.querySelector("input").addEventListener("change", function () {
if (this.files.length > 0) {
let fileObj = this.files[0];
let fd = new FormData();
fd.append("avatar", fileObj); //添加文件的话,要使用文件对象
axios.post("http://www.itcbc.com:3006/api/formdata", fd).then((result) => {
console.log(result.data);
});
}
});
</script>
</body>
文件域补充
文件域,就是 文件选择框,也就是
课堂代码:
<body>
<!--
accept属性:控制能够选择的文件类型
.jpg
.jpg,.png,.gif
image/png
image/*
-->
<!--
multiple属性:表示可以选择多个文件
-->
<input type="file" accept="image/*" multiple>
<script>
// 给文件选择框,注册事件的话,一般都用change事件
document.querySelector('input').addEventListener('change', function () {
// console.log(123)
// 在JS中,用什么表示、来描述一个文件???
// 文件有类型、有名字、大小、日期相关....,所以在JS中,使用对象表示文件
// ****** 确实是使用对象来表示文件;这个对象我们不用自己创建,通过文件选择框来获得 ******
// 获取文件对象(文件选择框的 files 属性表示我们选择的哪些个文件)
// console.log(文件选择框.files)
// console.log(document.querySelector('input').files)
// console.log(this.files)
/*
{
0: 文件对象,
1: 文件对象,
2: 文件对象,
.............. 到底有几个结果,取决于选择了几张图片
}
*/
if (this.files.length > 0) {
let fileObj = this.files[0]
console.log(fileObj) // 用这个对象,表示我们选择的第1张图片
}
})
// 表示一个人,用字符串、数组、函数、对象、布尔?????
// 用对象,因为人的特点太多了
</script>
</body>
本地预览:
document.querySelector('文件域').addEventListener('change', function () {
if (this.files.length > 0) {
let fileObj = this.files[0] // 找到文件对象
let url = URL.createObjectURL(fileObj) // 根据文件对象,创建url
document.querySelector('img').src = url
}
})
看接口文档设置请求参数和请求体
接口文档描述 | 具体到代码 |
---|---|
Query参数或查询参数 | 使用学过的 params 即可 = params: { id: 200, appkey: ‘laotang’} |
/api/getbooks/:id/:appkey | 只能自己拼接 = axios.get(‘/api/delbook/200/laotang’) |
/请求体或者body参数,application/x-www-form-urlencoded | axios({ url: ‘/api/ssss’,data: ‘key=value&key=value’}) |
请求体或者body参数application/json | axios({url: ‘/api/ddd’,data: { key: value, key: value }}) |
请求体或者body参数multipart/form-data | axios({url: ‘/api/ddd’,data: fd // fd 就是 new FormData()}) |
常见的响应状态码
状态码是后端同学设置的。
每一个后端同学对响应状态码的理解也是不同的。
所以,后面的学习中,或工作中,可能会遇到各种各样的状态码。
遇到什么状态码,可以去查一下:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status
ajax原生代码
Content-Type请求头
提交的请求体,有三种格式,提交请求体的时候,必须指定对应的 Content-Type 请求头。
每种请求体,都对应着各自的Content-Type。
● 提交JSON格式数据 --------- application/json ------- 需要程序员写
● 提交查询字符串格式 --------- application/x-www-form-urlencoded ------- 需要程序员写
● 提交FormData对象 -------- multipart/form-data ------- 不需要程序员写
原生的GET请求(带参数)
// GET 和 DELETE 是一样的语法
// 1. 实例化 XMLHttpRequest 对象
let xhr = new XMLHttpRequest()
// 2. 设置 load 事件,当服务器响应结果之后,会自动触发load事件(可以在load事件中接收响应结果)
xhr.addEventListener('load', function () {
let res = xhr.response // xhr.response 用于接收响应结果
console.log(res)
})
// 3. 调用open方法,设置请求方式和url地址 (设置请求行)
// xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks')
// 拼接url参数,格式: url?参数=值&参数=值&参数=值.......... (不能加任何的空格)
xhr.open('GET', 'http://www.itcbc.com:3006/api/getbooks?appkey=laot334ang')
// 4. 调用send方法,[设置请求体],发送请求
xhr.send()
原生POST请求
<body>
<button>添加图书</button>
<script>
document.querySelector('button').addEventListener('click', function () {
// 1. 实例化 XMLHttpRequest 对象
let xhr = new XMLHttpRequest()
// 2. 注册load事件,事件中,接收响应结果
xhr.addEventListener('load', function () {
let res = xhr.response
console.log(res)
})
// 3. 设置open,设置请求行
xhr.open('post', 'http://www.itcbc.com:3006/api/addbook')
// 4. 调用 setRequestHeader() 方法,设置请求体的编码格式
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
// xhr.setRequestHeader('Content-Type', 'application/json')
// 5. 调用send,设置请求体,发送请求
xhr.send('bookname=xx&author=yy&publisher=zz&appkey=laot334ang')
// xhr.send('{ "bookname": "xx", "author": "yy", "publisher": "zz", "appkey": "laot334ang" }')
})
/*
请求体,有三种格式:
1. bookname=xx&author=yy&publisher=zz&appkey=laot334ang
需要手动设置 xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
2. '{ "bookname": "xx", "author": "yy", "publisher": "zz", "appkey": "laot334ang" }'
需要手动设置 xhr.setRequestHeader('Content-Type', 'application/json')
3. new FormData()
不需要设置 setRequestHeader,浏览器会自动设置
*/
</script>
</body>
封装ajax源码
// 声明函数
// 调用函数的时候,传递了一个对象格式的实参,在传参的时候,相当于把实参赋值给形参
// let { method, url, params, data } = { method: 'GET', url: 'xxxx', params: {}, data: {} }
function ajax({ method, url, params, data, success }) {
// console.log(data)
// 调用函数的目的就是发送Ajax请求,所以,实现Ajax请求的一套代码得写好
let xhr = new XMLHttpRequest()
xhr.addEventListener('load', function () {
let res = JSON.parse(xhr.response) // 服务器返回的是JSON,这里转一下
// console.log(res)
success(res)
})
// 先处理params,把对象格式的params,转成查询字符串格式
let arr = []
for (let key in params) {
arr.push(`${key}=${params[key]}`)
}
xhr.open(method, url + '?' + arr.join('&'))
// 函数中,需要判断请求体的类型是什么类型的,因为不同的请求体类型,对应的 Conent-Type,send()都不同
if (data instanceof FormData) {
xhr.send(data)
} else if (typeof data === 'object') {
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(JSON.stringify(data)) // 需要把对象,转成JSON
} else if (typeof data === "string") {
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
xhr.send(data)
} else {
xhr.send()
}
}
// 调用函数,尽量的模拟axios的封装
let fd = new FormData()
fd.append('aaa', 'hello')
ajax({
method: 'POST',
url: 'http://www.itcbc.com:3006/api/formdata',
// 下面的params,有可能有
// params: { appkey: 'laot334ang' },
// 下面的data,模拟了可能的三种请求体
// data: { bookname: 'ss', author: 'yy', publisher: 'dd' },
// data: 'bookname=dd&author=yy&publisher=yys',
data: fd,
success: (result) => {
console.log(result)
}
})
同源策略和跨域请求
同源
同源,说的是两个url之间的对比。如果两个url以下三个方面都相同,则这两个url同源,否则非同源。
● 协议(http、https、file、…)
● 主机地址(www.itcbc.com)
● 端口号(:3006)
http协议默认的端口是 80; https协议默认的端口是 443
同源策略
同源策略(同源政策)是浏览器的一种保护机制。
如果发送了一个请求,服务器返回结果后,浏览器会判断(检查)打开页面的url 和 请求的接口地址是否同源。
● 如果同源则接收响应结果
● 如果不同源,则拒绝接收结果(造成请求失败)
跨域
定义
凡是违反了同源策略的请求,都是跨域请求。
我们这几天,请求的接口,都是跨域请求。正常来讲,都会请求失败。
目前,能够请求成功,是因为做了处理(见下文)
突破跨域的限制
正常情况下(不做任何处理的情况下),跨域请求,都不能实现。
工作中,几乎都是跨域请求。
那怎么办?
所以,我们肯定要突破跨域请求的限制才行,否则就无法正常工作了。
突破跨域的限制,可以使用JSONP方案 或 CORS方案。
CORS方案(用的多)
● 用的多
● 是标准的解决跨域的方案
● 兼容性不好(IE10+)
● 支持所有的请求方式
● 用起来方便的不要不要的
我们课程中使用的全部接口都是使用CORS方案实现的
使用CORS方案解决跨域
● 只需要后端程序员在做出响应的时候,加一个响应头(Access-Control-Allow-Origin: *)即可。
● 前面程序员不需要做任何处理,正常发送Ajax请求即可。
JSONP方案(用的少)
● 用的少
● 不是标准的解决跨域的方案
● 是一个很古老的方案
● JSONP请求,和Ajax无关,只支持GET请求。
● 了解一下实现原理即可
实现原理:
● 准备好一个函数,名字随意(比如叫做abcd),用于接收响应结果
● 使用script标签的src属性请求接口地址,并通过callback把函数名传给服务器即可
<script>
// 提前准备好 abc 函数
function abcd(res) {
console.log(res)
}
// abcd({ "id": 100, "name": "hahaha", "age": 20 });
// 你的函数名是abcd,参数是响应给你的数据哦~~~
</script>
<script src="http://www.itcbc.com:3006/api/jsonp?callback=abcd"></script>
封装一个发送JSONP请求的函数(锻炼编程能力)
function jsonp({ url, params, success }) {
// 处理params
let arr = []
for (let key in params) {
arr.push(`${key}=${params[key]}`)
}
// console.log(success)
// 准备好的函数是 success
// 服务器返回 success(.....) ,调用的是全局中的 success
// 所以需要把我们的success升级为全局函数
window.success = success
let s = document.createElement('script')
s.src = url + '?callback=success&' + arr.join('&')
document.body.appendChild(s)
// script标签什么时候加载完毕。当服务器返回结果后,表示script标签加载的内容加载完毕了
// 加载完服务器返回的结果,就会触发 load 事件
s.addEventListener('load', function () {
document.body.removeChild(s)
})
}
// 点击按钮,调用函数,进行测试
document.querySelector('button').addEventListener('click', function () {
jsonp({
url: 'http://www.itcbc.com:3006/api/jsonp',
params: {
id: 1,
appkey: 'laotang'
},
success: function (res) {
console.log(res)
}
})
})
淘宝搜索建议案例
// 分析:
// 1. 找到输入框,注册input事件(当我们在输入框输入内容的时候就会触发事件)
document.querySelector('.ipt').addEventListener('input', function () {
// 获取搜索关键字
let keyword = this.value
// 2. 事件触发后,发送JSONP请求,获取搜索建议
jsonp({
url: 'https://suggest.taobao.com/sug',
params: {
q: keyword,
code: 'utf-8'
},
success: (res) => {
// 3. 得到搜索建议之后,把数据渲染到 div#suggest-list 中
// console.log(res)
let arr = res.result.map(item => `<div class="suggest-item">${item[0]}</div>`)
// console.log(arr.join(''))
document.querySelector('#suggest-list').innerHTML = arr.join('')
}
})
})
节流案例
let box = document.querySelector('.box')
let btn = document.querySelector('.btn-fire')
btn.addEventListener('click', function () {
console.log(1)
// 判断 box 盒子里面有几个图片
if (box.children.length === 2) return
// 创建一个热狗
let newBall = document.createElement('img')
newBall.src = './img/bullet.png'
newBall.classList.add('ball')
// 将热狗加入到盒子中
box.appendChild(newBall)
// 给热狗加一个动画
for (let i = 1; i <= 95; i++) {
setTimeout(() => {
newBall.style.left = i + '%'
if (i === 95) {
// 当热狗跑到头,移除它
box.removeChild(newBall)
}
}, i * 10)
}
})
通过时间差实现节流
// 节流:单位时间(30ms)内,事件中的计算,最多执行一次
let img = document.querySelector('img')
let prev = Date.now() // 1000130
// 给 document 注册 mousemove 事件,当鼠标移动的时候触发
document.addEventListener('mousemove', function (e) {
console.log(111)
let curr = Date.now() // 1000130
if (curr - prev >= 30) {
console.log(222)
// 获取鼠标的位置
let x = e.clientX
let y = e.clientY
// console.log(x, y)
// 设置图片的 left 样式和 top 样式
img.style.left = (x - 30) + 'px'
img.style.top = (y - 30) + 'px'
// 重置上一次执行时间
prev = Date.now()
}
})