文章目录
- 1. jsonp的封装
- 1. 1 JSONP函数的封装
- 2 . 认识axios
- 2 .1 功能特点:
- 2 .2 axiox请求方式
- 2 .3 axios的get与post请求
- 3 . axios发送基本请求
- 3. 1 发送get请求
- 3. 2 使用axios 完成高并发请求
- 3. 3.全局配置
- 4 . axios请求配置项
- 5 . 响应的结构
- 6 . axios实例与封装
- 6. 1 axios 的实例
- 6. 2 axios封装
- 6. 2. 1 axios的依赖性
- 6. 2. 2 单独封装
- 7 . 拦截器
- 7. 1.如何使用拦截器?
- 7. 2 拦截器中都做什么呢? (1)
- 7. 3.拦截器中都做什么呢? (2)
- 8 . 补充
- 8 .1 axios的底层原理
- 8 .2 获取响应状态的属性...
- 8 .2 .1 本地图片
- 8 .2 .2 网页跳转
- 8 .3 图书列表
- 1 图书列表
- 2 添加图书
- 3 删除图书
- 8 .4关于拦截器的简单使用(后期优化)
- 8 .4 .1 拦截器Loading的使用
- 8 .4 .1 .1 全局基地址补充说明
- 8 .5文件的上传
- 8 .5 .1FormDataAPI中的append方法
- 8 .5 .2文件的预览
1. jsonp的封装
在前端开发中, 我们一种常见的网络请求方式就是JSONP
- 使用JSONP最主要的原因往往是为了解决
跨域
访问的问题.
SONP的原理是什么呢?
- JSONP的核心在于通过
<script>
标签的src来帮助我们请求数据. - 原因是我们的项目部署在domain1.com服务器上时, 是不能直接访问domain2.com服务器上的资料的.
- 这个时候, 我们利用
<script>
标签的src
帮助我们去服务器请求到数据, 将数据当做一个javascript的函数来执行,并且执行的过程中传入我们需要的json. - 所以, 封装jsonp的核心就在于我们监听
window上的jsonp
进行回调时的名称.
1. 1 JSONP函数的封装
2 . 认识axios
2 .1 功能特点:
- 在浏览器中发送 XMLHttpRequests 请求
- 在 node.js 中发送 http请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
2 .2 axiox请求方式
- axios(config)
- axios.request(config)
- axios.get(url[, config])
- axios.delete(url[, config])
- axios.head(url[, config])
- axios.post(url[, data[, config]])
- axios.put(url[, data[, config]])
- axios.patch(url[, data[, config]])
2 .3 axios的get与post请求
3 . axios发送基本请求
- 全局安装axios
// 安装axios
npm install axios --save
3. 1 发送get请求
- axios的基本使用 axios(config)
import axios from 'axios'
// 1.axios的基本使用 axios(config)
axios({
url: 'http://123.207.32.32:8000/home/multidata', // 项目接口
// 默认是get请求 可以用method指定
// method: 'post'
}).then(res => { // 获取返回的数据
console.log(res);
})
- 专门针对get请求的参数拼接
axios({
// url:'http://123.207.32.32:8000/home/data?type=sell&page=1'
// 参数除了可以直接拼接在url,也可以用params
url: 'http://123.207.32.32:8000/home/data',
// 专门针对get请求的参数拼接
params: {
type: 'pop',
page: 1
}
}).then(res => {
console.log(res);
})
新的API:
- 无参数:
https:www.blogry.cn/test/index
- 有参数
https:www.blogry.cn/test/blog?title
3. 2 使用axios 完成高并发请求
function getUserAccount() {
return axios.get('/user/12345');
}
function getUserPermissions() {
return axios.get('/user/12345/permissions');
}
axios.all([getUserAccount(), getUserPermissions()])
.then(axios.spread(function (acct, perms) {
// 两个请求现在都执行完成
}));
- 处理并发请求的助手函数:
axios.all(iterable) //两个请求必须执行
axios.spread(callback) //
axios.all
方法接受一个数组作为参数,数组中的每个元素都是一个请求,返回一个 promise 对象,当数组中所有请求均已完成时,执行 then 方法。 在 then 方法中执行了axios.spread
方法。
axios.spread
方法。该方法是接收一个函数作为参数,返回一个新的函数。接收的参数函数的参数是axios.all方法中每个请求返回的响应。
有时候我们可能需求同时发送两个请求
- 使用
axios.all
, 可以放入多个请求的数组. axios.all([])
返回的结果是一个数组,使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2
// timeout请求超时 进行全局配置
axios.defaults.timeout=5000;
// 相同地址的情况下也可以进行全局配置
// axios.defaults.baseURL=''
axios.all([axios({
// timeout:5000,
url:'http://123.207.32.32:8000/home/multidata',
}),
axios({
url:'https://www.blogry.cn/test/blog',
// timeout:5000,
// https://www.blogry.cn/test/blog?title=
params:{
type:'title',
page:5
}
})
])
// 并发请求拿到两条数据
// .then(data=>{
// console.log(data);
// })
// 对两条数据 进行单独打印
.then(axios.spread((rel1,rel2)=>{
console.log(rel1);//url:'http://123.207.32.32:8000/home/multidata',
console.log(rel2);//url:'https://www.blogry.cn/test/blog',
}))
3. 3.全局配置
- 在上面的示例中, 我们的BaseURL是固定的
- 事实上, 在开发中可能很多参数都是固定的.
- 这个时候我们可以进行一些抽取, 也可以利用axiox的全局配置
axios.defaults.baseURL = ‘123.207.32.32:8000’
axios.defaults.headers.post[‘Content-Type’] = ‘application/x-www-form-urlencoded’;
// 3.使用全局的axios和对应的配置在进行网络请求
axios.defaults.baseURL = 'http://123.207.32.32:8000'
axios.defaults.timeout = 5000 // 超时
axios.all([axios({
url: '/home/multidata'
}), axios({
url: '/home/data',
params: {
type: 'sell',
page: 5
}
})]).then(axios.spread((res1, res2) => {
// 使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2
console.log(res1);
console.log(res2);
}))
4 . axios请求配置项
- 创建请求时可用的配置选项,注意只有 url 是必需的。
- 如果没有指定 method,请求将默认使用 get 方法。
{
// `url` 是用于请求的服务器 URL
url: "/user",
// `method` 是创建请求时使用的方法
method: "get", // 默认是 get
// `baseURL` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL。
// 它可以通过设置一个 `baseURL` 便于为 axios 实例的方法传递相对 URL
baseURL: "https://some-domain.com/api/",
// `transformRequest` 允许在向服务器发送前,修改请求数据
// 只能用在 "PUT", "POST" 和 "PATCH" 这几个请求方法
// 后面数组中的函数必须返回一个字符串,或 ArrayBuffer,或 Stream
transformRequest: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `transformResponse` 在传递给 then/catch 前,允许修改响应数据
transformResponse: [function (data) {
// 对 data 进行任意转换处理
return data;
}],
// `headers` 是即将被发送的自定义请求头
headers: {"X-Requested-With": "XMLHttpRequest"},
// `params` 是即将与请求一起发送的 URL 参数
// 必须是一个无格式对象(plain object)或 URLSearchParams 对象
params: {
ID: 12345
},
// `paramsSerializer` 是一个负责 `params` 序列化的函数
// (e.g. https://www.npmjs.com/package/qs, http://api.jquery.com/jquery.param/)
paramsSerializer: function(params) {
return Qs.stringify(params, {arrayFormat: "brackets"})
},
// `data` 是作为请求主体被发送的数据
// 只适用于这些请求方法 "PUT", "POST", 和 "PATCH"
// 在没有设置 `transformRequest` 时,必须是以下类型之一:
// - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
// - 浏览器专属:FormData, File, Blob
// - Node 专属: Stream
data: {
firstName: "Fred"
},
// `timeout` 指定请求超时的毫秒数(0 表示无超时时间)
// 如果请求花费了超过 `timeout` 的时间,请求将被中断
timeout: 1000,
// `withCredentials` 表示跨域请求时是否需要使用凭证
withCredentials: false, // 默认的
// `adapter` 允许自定义处理请求,以使测试更轻松
// 返回一个 promise 并应用一个有效的响应 (查阅 [response docs](#response-api)).
adapter: function (config) {
/* ... */
},
// `auth` 表示应该使用 HTTP 基础验证,并提供凭据
// 这将设置一个 `Authorization` 头,覆写掉现有的任意使用 `headers` 设置的自定义 `Authorization`头
auth: {
username: "janedoe",
password: "s00pers3cret"
},
// `responseType` 表示服务器响应的数据类型,可以是 "arraybuffer", "blob", "document", "json", "text", "stream"
responseType: "json", // 默认的
// `xsrfCookieName` 是用作 xsrf token 的值的cookie的名称
xsrfCookieName: "XSRF-TOKEN", // default
// `xsrfHeaderName` 是承载 xsrf token 的值的 HTTP 头的名称
xsrfHeaderName: "X-XSRF-TOKEN", // 默认的
// `onUploadProgress` 允许为上传处理进度事件
onUploadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `onDownloadProgress` 允许为下载处理进度事件
onDownloadProgress: function (progressEvent) {
// 对原生进度事件的处理
},
// `maxContentLength` 定义允许的响应内容的最大尺寸
maxContentLength: 2000,
// `validateStatus` 定义对于给定的HTTP 响应状态码是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者设置为 `null` 或 `undefined`),promise 将被 resolve; 否则,promise 将被 rejecte
validateStatus: function (status) {
return status >= 200 && status < 300; // 默认的
},
// `maxRedirects` 定义在 node.js 中 follow 的最大重定向数目
// 如果设置为0,将不会 follow 任何重定向
maxRedirects: 5, // 默认的
// `httpAgent` 和 `httpsAgent` 分别在 node.js 中用于定义在执行 http 和 https 时使用的自定义代理。允许像这样配置选项:
// `keepAlive` 默认没有启用
httpAgent: new http.Agent({ keepAlive: true }),
httpsAgent: new https.Agent({ keepAlive: true }),
// "proxy" 定义代理服务器的主机名称和端口
// `auth` 表示 HTTP 基础验证应当用于连接代理,并提供凭据
// 这将会设置一个 `Proxy-Authorization` 头,覆写掉已有的通过使用 `header` 设置的自定义 `Proxy-Authorization` 头。
proxy: {
host: "127.0.0.1",
port: 9000,
auth: : {
username: "mikeymike",
password: "rapunz3l"
}
},
// `cancelToken` 指定用于取消请求的 cancel token
// (查看后面的 Cancellation 这节了解更多)
cancelToken: new CancelToken(function (cancel) {
})
}
5 . 响应的结构
{
// `data` 由服务器提供的响应
data: {},
// `status` HTTP 状态码
status: 200,
// `statusText` 来自服务器响应的 HTTP 状态信息
statusText: "OK",
// `headers` 服务器响应的头
headers: {},
// `config` 是为请求提供的配置信息
config: {}
}
- 使用 then 时,会接收下面这样的响应:
axios.get("/user/12345")
.then(function(response) {
console.log(response.data);
console.log(response.status);
console.log(response.statusText);
console.log(response.headers);
console.log(response.config);
})
6 . axios实例与封装
6. 1 axios 的实例
为什么要创建axios的实例呢?
- 当我们从axios模块中导入对象时, 使用的实例是默认的实例.
- 当给该实例设置一些默认配置时, 这些配置就被固定下来了.
- 但是后续开发中, 某些配置可能会不太一样.
- 比如某些请求需要使用特定的baseURL或者timeout或者content-Type等.
- 这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息.
代码
:
// 为什么要创建axios实例?有些请求的配置可能会不同,大项目会有多个服务器,服务器的ip不同,baseURL也就不同
// 在开发时,因为请求接口比较多且业务比较复杂
// 因此需要局部的请求方式来进行这就需要进行创建axios实例进行
// 优点是
// 把每一个axios实例进行单一化, 不管是在改变地址(url)时,还是改变请求响应时间都能做到单独的模块不会影响到别的请求
axios.defaults.baseURL = 'http://222.111.33.33:8000'
axios.defaults.timeout = 10000
axios({
url: 'http://123.207.32.32:8000/category'
})
// 4.创建对应的axios的实例
const instance1 = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
instance1({
url: '/home/multidata'
}).then(res => {
console.log(res);
})
instance1({
url: '/home/data',
params: {
type: 'pop',
page: 1
}
}).then(res => {
console.log(res);
})
const instance2 = axios.create({
baseURL: 'http://222.111.33.33:8000',
timeout: 10000,
headers: {}
})
6. 2 axios封装
6. 2. 1 axios的依赖性
App.vue
<template>
<div id="app">
<div>{{ result }}</div>
<h2>-----------------------------------|</h2>
<hello-world />
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
import axios from 'axios'
export default {
name: 'App',
components: {
HelloWorld
},
data() {
return {
result: ''
}
},
created() {
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}).then(res => {
// console.log(res);
this.result = res;
})
}
}
</script>
<style>
</style>
HelloWord.vue
<template>
<div class="hello">
{{hellow}}
</div>
</template>
<script>
import axios from 'axios'
export default {
name: 'HelloWorld',
data() {
return {
hellow: ''
}
},
created() {
axios({
url: 'http://123.207.32.32:8000/home/multidata'
}).then(res => {
// console.log(res);
this.hellow = res;
})
}
}
</script>
<style scoped>
</style>
- 在上述开发中这种开发思路不好,每个组件对第三方框架依赖太强了,假如这个框架不再维护,或者有bug,更换框架得一个个文件查找修改
- 因此我们要有这种开发意识:
只要引用第三方的东西,千万不要在多个组件对它有依赖
6. 2. 2 单独封装
- 新建network文件夹,里面新建文件request.js
request封装v1.0 使用回调,返回数据
// request.js
import axios from 'axios'
// request封装v1.0 使用回调,返回数据
export function request(config, success, failure) {
// 1.创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 发送真正的网络请求
instance(config)
.then(res => {
// console.log(res);
success(res);
})
.catch(err => {
// console.log(err);
failure(err)
})
}
// main.js
// 5.封装request模块
import {
request
} from "./network/request";
// request封装v1.0 的调用
request({
url: '/home/multidata'
}, res => {
console.log(res);
}, err => {
console.log(err);
})
request封装v2.0 直接传一个config 再从里面取success,failure
// request.js
// request封装v2.0 直接传一个config 再从里面取success,failure
export function request(config) {
// 1.创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 发送真正的网络请求
instance(config.baseConfig)
.then(res => {
// console.log(res);
config.success(res);
})
.catch(err => {
// console.log(err);
config.failure(err)
})
}
// main.js
// request封装v2.0 的调用
request({
baseConfig: {
url:'/home/multidata'
},
success: function (res) {
console.log(res);
},
failure: function (err) {
console.log(res);
}
})
request封装v3.0 使用Promise
// request.js
// request封装v3.0 使用Promise
export function request(config) {
return new Promise((resolve, reject) => {
// 1.创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 发送真正的网络请求
instance(config)
.then(res => {
resolve(res)
})
.catch(err => {
reject(err)
})
})
}
// main.js
request({
url: '/home/multidata'
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
request封装v4.0 直接return instance(config) 因为它这个本身就是一个Promise
// request.js
// request封装v4.0 直接return instance(config) 因为它这个本身就是一个Promise
export function request(config) {
// 1.创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 2.发送真正的网络请求
return instance(config) // 本身的返回值就是个promise
}
// main.js
// request封装v3.0 / v4.0的调用
request({
url: '/home/multidata'
}).then(res => {
console.log(res);
}).catch(err => {
// console.log(err);
})
7 . 拦截器
7. 1.如何使用拦截器?
- axios提供了拦截器,用于我们在发送每次请求或者得到相应后,进行对应的处理。
在请求或响应被 then 或 catch 处理前拦截它们。
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
移除拦截器
var myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
自定义 axios 实例添加拦截器
var instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});
7. 2 拦截器中都做什么呢? (1)
请求拦截可以做到的事情:
- 请求拦截中错误拦截较少,通常都是配置相关的拦截
- 可能的错误比如请求超时,可以将页面跳转到一个错误页面中。
7. 3.拦截器中都做什么呢? (2)
- 响应拦截中完成的事情:
- 响应的成功拦截中,主要是对数据进行过滤。
- 响应的失败拦截中,可以根据status判断报错的错误码,跳转到不同的错误提示页面。
代码
// request.js
export function request(config) {
// 1.创建axios的实例
const instance = axios.create({
baseURL: 'http://123.207.32.32:8000',
timeout: 5000
})
// 2.axios的拦截器
// 2.1.请求拦截的作用 成功/失败
instance.interceptors.request.use(config => {
// console.log(config);
// 1.比如config中的一些信息不符合服务器的要求
// 2.比如每次发送网络请求时, 都希望在界面中显示一个请求的图标
// 3.某些网络请求(比如登录(token)), 必须携带一些特殊的信息
// 得把config再返回
return config
}, err => {
// console.log(err);
})
// 2.2.响应拦截 成功/失败
instance.interceptors.response.use(res => {
// console.log(res);
return res.data
}, err => {
console.log(err);
})
// 3.发送真正的网络请求
return instance(config) // 本身的返回值就是个promise
}
// main.js
// request封装v3.0 / v4.0的调用
request({
url: '/home/multidata'
}).then(res => {
console.log(res);
}).catch(err => {
// console.log(err);
})
新接口 :
`http://123.207.32.32:8000/home/multidata`
无参数:`https:www.blogry.cn/test/index`
有参数 `https:www.blogry.cn/test/blog?title=我的编程经历`
8 . 补充
8 .1 axios的底层原理
- axios的底层还是ajax
ajax详解
8 .2 获取响应状态的属性…
8 .2 .1 本地图片
8 .2 .2 网页跳转
- 网页跳转进行id传值
- 利用
id
的传值来决定显示的内容步骤index代码解析
const onloadArr = () => {
axios({
url: 'https://autumnfish.cn/fruitApi/fruits',
method: 'get',
// data: { 'post请求参数'},
// params: { 'get请求参数'}
}).then(res => {
//成功回调
console.log(res)
// 进行数组的迭代,把数组转为字符串进行拼接
document.querySelector('.tbody').innerHTML = res.data.data.map((item,index) => {
// 进行解构
const { name, info, icon,id } = item
return `
<div class="tr">
<div class="td">${name}</div>
<div class="td">
<img alt="" src="${icon}" />
</div>
<div class="td">
<span class="my-input__inner count">${info}</span>
</div>
<div class="td">
<button class="info" data-index="${index}" οnclick=" location.href='./detail.html?id=${id}'">查看详情</button>
</div>
</div>
`
}).join('')
})
}
onloadArr()
跳转的detail.html代码解析
// 进行分割拿取后面的id
const id=location.search.split('=')[1]
console.log(id);
axios({
// 注意这里是直接传id 不经过字符串的拼接
url:`https://autumnfish.cn/fruitApi/fruit/${id}`,
method:'get',
// params: { 'get请求参数'}
}).then(res=>{
//成功回调
console.log(res)
document.querySelector('.info').innerHTML=`
<div class="bg">
<div class="name" style="color:red">水果名称:${res.data.data.name}</div>
<div class="img">
<img
src="${res.data.data.icon}"
alt=""
/>
</div>
<p style="color:red">水果信息:${res.data.data.info}</p>
<div class="story">
<h5>详细介绍:</h5>
<p>
${res.data.data.desc}
</p>
</div>
</div>
`
})
8 .3 图书列表
图书管理基地址: http://ajax-base-api-t.itheima.net
备用基地址 : http://www.liulongbin.top:3006
1 图书列表
- 接口URL: /api/getbooks
- 调用方式: GET
- 参数格式:
参数名称 | 参数类型 | 是否必选 | 参数说明 |
id | Number | 否 | 图书Id |
bookname | String | 否 | 图书名称 |
author | String | 否 | 作者 |
publisher | String | 否 | 出版社 |
- 响应格式:
数据名称 | 数据类型 | 说明 |
status | Number | 200 成功;500 失败; |
msg | String | 对 status 字段的详细说明 |
data | Array | 图书列表 |
+id | Number | 图书Id |
+bookname | String | 图书名称 |
+author | String | 作者 |
+publisher | String | 出版社 |
- 返回示例:
{
"status": 200,
"msg": "获取图书列表成功",
"data": [
{ "id": 1, "bookname": "西游记", "author": "吴承恩", "publisher": "北京图书出版社" },
{ "id": 2, "bookname": "红楼梦", "author": "曹雪芹", "publisher": "上海图书出版社" },
{ "id": 3, "bookname": "三国演义", "author": "罗贯中", "publisher": "北京图书出版社" }
]
}
参考代码
function booksList() {
axios({
url: "http://ajax-base-api-t.itheima.net/api/getbooks",
method: "get",
}).then((res) => {
//成功回调
readerData(res.data.data);
// console.log();
console.log(res.data.data[0].id);
});
}
booksList();
// 封装渲染函数
const readerData = (arr) => {
document.querySelector("tbody").innerHTML = arr.map(
(item) => `
<tr>
<th scope="row">${item.id}</th>
<td>${item.bookname}</td>
<td>${item.author}</td>
<td>${item.publisher}</td>
<td>
<button type="button" class="btn btn-link btn-sm" data-index="${item.id}">删除</button>
</td>
</tr>
`
);
};
2 添加图书
- 接口URL: /api/addbook
- 调用方式: POST
- 参数格式:
参数名称 | 参数类型 | 是否必选 | 参数说明 |
bookname | String | 是 | 图书名称 |
author | String | 是 | 作者 |
publisher | String | 是 | 出版社 |
- 响应格式:
数据名称 | 数据类型 | 说明 |
status | Number | 201 添加成功;500 添加失败; |
msg | String | 对 status 字段的详细说明 |
- 返回示例:
{
"status": 201,
"msg": "添加图书成功"
}
添加图书列表参考代码
/ 添加图书列表
document.querySelector(".btn-dark").addEventListener("click", function (e) {
e.preventDefault();
// 获取书名,作者,出版社的框
const bookname = document.querySelector("#sname").value.trim();
const author = document.querySelector("#username").value.trim();
const publisher = document.querySelector("#press").value.trim();
// 对象进行解构赋值
// 进行非空判断
if (bookname.length === 0 || author.length === 0 || publisher.length === 0) {
return alert("null");
}
const data = { bookname, author, publisher };
// 二层优化=>
// map 映射数组
//foreach遍历数组
//some判断数组中是否有元素满足条件 有则真
// TypeError 数据类型错误
// 语法: Object.value(data)返回的是数组 =>取对象中的所有的属性值
// Object.keys取的是属性名
// 2 Object.value(data).some(item=>item==='')返回真或者假
axios({
url: "http://ajax-base-api-t.itheima.net/api/addbook",
method: "post",
// data可以用解构进行处理
data,
})
.then((res) => {
console.log(res);
// 请求成功后发送get请求
// 进行列表的重新渲染
if (res.data.status === 201) {
booksList();
// 表单清空处理reset用于form表单的清空处理
document.querySelector("form").reset();
} else alert(res.data.msg);
})
.catch((err) => {
alert("接口请求失败");
});
});
3 删除图书
- 接口URL: /api/delbook
- 调用方式: GET
- 参数格式:
参数名称 | 参数类型 | 是否必选 | 参数说明 |
id | Number | 是 | 图书Id |
- 响应格式:
数据名称 | 数据类型 | 说明 |
status | Number | 200 删除成功;500 未指定要删除的图书Id;501 执行Sql报错;502 要删除的图书不存在; |
msg | String | 对 status 字段的详细说明 |
- 返回示例:
{
"status": 200,
"msg": "删除图书成功!"
}
删除图书参考代码
// 删除列表
document.querySelector("tbody").addEventListener("click", function (e) {
console.log(e.target);
// 事件委托 右侧是操作所需要的dom元素
if ((e.target.tagName = "BUTTON")) {
let id = e.target.dataset.index
// console.log(e.target.parentNode.remove());
axios({
url: "http://ajax-base-api-t.itheima.net/api/delbook",
method: "get",
params: {id},
}).then((res) => {
//成功回调
console.log(res);
if (res.data.status === 200) {
booksList();
// 表单清空处理reset用于form表单的清空处理
document.querySelector("form").reset();
} else alert(res.data.msg);
});
}
});
8 .4关于拦截器的简单使用(后期优化)
axios拦截器工作流程
- axios 发起请求
- 执行 请求拦截器 : 添加ajax发送请求之前的操作
- 服务器 接收、处理、响应 请求
- 执行 响应拦截器 : 添加服务器响应之后的操作
- axios 接收响应(执行then方法)
拦截器的经典应用场景
- 免登录 =>
相当于token储存值
- loading的应用
8 .4 .1 拦截器Loading的使用
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
document.querySelector('.loading-box').style.display = 'block'
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
document.querySelector('.loading-box').style.display = 'none'
return response;
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
8 .4 .1 .1 全局基地址补充说明
- 配置全局的基地址
axios.defaults.baseURL = 'https://autumnfish.cn/fruitApi/fruits'
- 在配置全局的基地址后 如何
url
没有这个地址将采用全局的基地址(baseURL)
进行拼接,要是有了就默认采用url
的地址
8 .5文件的上传
- 文件上传的input框
accept 属性表示可选择的文件类型
image表示只允许选择图片类型的文件
<input type="file" id="iptFile" accept="image/*" multiple />
重要点 :
在文件上传时我们需要new一个FormData
对象 , 以此来保存文件
const app = new FormData();
在创建FormData
对象后可以使用FormData.append来添加键/值对到表单里面;
// 向对象中添加属性=>active属性名:this.files[0]属性值
app.append("active", this.files[0]);
8 .5 .1FormDataAPI中的append方法
- FormData 接口的append() 方法 会添加一个新值到 FormData对象内的一个已存在的键中,如果键不存在则会添加该键。
- FormData.set 和 append() 的区别在于,如果指定的键已经存在, FormData.set 会使用新值覆盖已有的值,而 append() 会把新值添加到已有值集合的后面。
append
接受的三个参数
formData.append(name, value); // 属性名 ,属性值
formData.append(name, value, filename); //第三个参数可选=>传给服务器的文件名称
// 头像上传
// 表单注册change事件
// 步骤: 1 注册change事件
// 拿取下标利用this.files[下标的索引]
// 3 new 一个FormData对象
document.querySelector("#iptFile").addEventListener("change", function () {
console.log(this.files);
// console.log(this.files[0]);
// 使用FormData对象添加文件
const app = new FormData();
// 向对象中添加属性=>active属性名:this.files[0]属性值
app.append("active", this.files[0]);
axios({
method: "post",
url: "http://www.liulongbin.top:3009/api/upload/avatar",
data: app,
}).then((res) => {
console.log(res);
document.querySelector(
"img"
).src = `http://www.liulongbin.top:3009${res.data.url}`;
});
});
优化文件上传=>点击图片上传
- 步骤一 : 点击图片按钮相当于点击了input框上传文件按钮
// 这里点击上传图片按钮相当于点击了 document.querySelector("#iptFile").click()
document.querySelector('#btnChoose').addEventListener('click', function () {
document.querySelector("#iptFile").click()
})
- 步骤二 : 扩大
input
的范围既用label
标签包裹
<label for="iptFile">
<img src="./images/cover.jpg" class="img-thumbnail thumb" alt="" />
<div class="mt-2">
<input type="file" name="iptFile" id="iptFile" accept="image/*" style="display: none" />
</label>
参考代码块
// 这里点击上传图片按钮相当于点击了 document.querySelector("#iptFile").click()
document.querySelector('#btnChoose').addEventListener('click', function () {
document.querySelector("#iptFile").click()
})
// 第三种方式点击图片上传利用label 标签
// 1 label标签扩大了点击范围,当点击图片时也能上传图像
// label中的for属性中的id相当于绑定了input中的id =>既点击图片就相当于点击了input框的上传
document.querySelector("#iptFile").addEventListener("change", function () {
console.log(this.files);
// console.log(this.files[0]);
// 使用FormData对象添加文件
const app = new FormData();
// 向对象中添加属性=>active属性名:this.files[0]属性值
app.append("active", this.files[0]);
axios({
method: "post",
url: "http://www.liulongbin.top:3009/api/upload/avatar",
data: app,
}).then((res) => {
console.log(res);
document.querySelector(
"img"
).src = `http://www.liulongbin.top:3009${res.data.url}`;
});
});
append
方法:文件和属性值的联合使用
- 第二个参数中直接添加属性值 | 文件
// new FormData对象发送文件
const app = new FormData()
app.append('heroName', document.querySelector('#heroName').value.trim())
app.append('heroSkill', document.querySelector('#heroSkill').value.trim())
app.append('heroIcon', document.querySelector('#heroIcon').files[0])
console.log(app)
8 .5 .2文件的预览
// 预览图片
//(1) 给file表单注册onchange事件
document.querySelector('#heroIcon').addEventListener('change', function () {
//(2)获取用户选择的文件
let file = this.files[0]
//(3)将file文件转成url路径
let url = URL.createObjectURL(file)
console.log(url);
//(4)把url路径设置给img标签src
document.querySelector('.preview').src = url
})