文章目录

  • 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函数的封装

axios请求jsonp接口 axios使用jsonp_ios


axios请求jsonp接口 axios使用jsonp_ios_02

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请求jsonp接口 axios使用jsonp_axios请求jsonp接口_03

  • 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’;

axios请求jsonp接口 axios使用jsonp_ios_04

// 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请求jsonp接口 axios使用jsonp_javascript_05


代码 :

// 为什么要创建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 单独封装

axios请求jsonp接口 axios使用jsonp_json_06

  • 新建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);
})

axios请求jsonp接口 axios使用jsonp_ios_07

  • 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);
})

axios请求jsonp接口 axios使用jsonp_axios请求jsonp接口_08

7 . 拦截器

7. 1.如何使用拦截器?

  • axios提供了拦截器,用于我们在发送每次请求或者得到相应后,进行对应的处理。

axios请求jsonp接口 axios使用jsonp_json_09


在请求或响应被 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)

请求拦截可以做到的事情:

axios请求jsonp接口 axios使用jsonp_json_10

  • 请求拦截中错误拦截较少,通常都是配置相关的拦截
  • 可能的错误比如请求超时,可以将页面跳转到一个错误页面中。

7. 3.拦截器中都做什么呢? (2)

  • 响应拦截中完成的事情:
  • 响应的成功拦截中,主要是对数据进行过滤。

axios请求jsonp接口 axios使用jsonp_javascript_11

  • 响应的失败拦截中,可以根据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的底层原理

8 .2 获取响应状态的属性…

8 .2 .1 本地图片

axios请求jsonp接口 axios使用jsonp_javascript_12

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
    })