Vue项目中Api的组织和返回数据处理的操作

 更新时间:2019年11月04日 10:02:25   作者:jenemy  
这篇文章主要介绍了Vue项目中Api的组织和返回数据处理的操作,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下

项目中的所有Api配置放在一个文件中,便于查找和修改,Api的版本从配置文件(config.js)中读取,采用 apiPrefix + url 的形式组成。

在配置文件中,Api 的配置采用 Http请求方式 url 的方式,默认情况下 GET 可以不写,请求方式统一采用大写形式,动态参数采用 : 占位符 的形式。

// services/api.js
export default {
 login: 'POST /login',
 logout: '/logout',
 queryUser: '/user/:id'
}

然后需要一个方法在解析上面的Api配置

// services/index.js
import request from '../utils/request'
import api from './api'
const gen = params => {
 let url = params
 let method = 'GET'
 const paramsArr = params.split(' ')
 if (paramsArr.length === 2) {
  method = paramsArr[0]
  url = paramsArr[1]
 }
 return data => {
  return request({
   url,
   data,
   method
  })
 }
}
const apiFunc = {}
for (const key in api) {
 apiFunc[key] = gen(api[key])
}
export default apiFunc

上面代码中的 request 是封装 axios 后暴露出来的方法,代码如下:

// utils/request.js
import axios from 'axios'
import store from '../store'
import { apiPrefix } from './config'
import { Message, MessageBox } from 'element-ui'
let cancel
const CancelToken = axios.CancelToken
const service = axios.create({
 baseURL: apiPrefix,
 timeout: 3000,
 cancelToken: new CancelToken(c => cancel = c)
})
service.interceptors.response.use(
 response => {
  const resType = response.config.responseType
  const res = response.data
  // 二进制文件
  if (resType && resType !== 'json') {
   const filename = response.headers['content-disposition'].split('filename=')[1]
   return {
    filename,
    blob: res
   }
  }
  if (res.code !== 200) {
   // 登录失效
   if (res.code === 401) {
    let timer = null
    // 取消后续请求
    cancel(res.msg)
    // 更新store及localStorage状态
    store.commit('user/RESET_LOGIN_STATE', false)
    MessageBox.confirm('登录已失效,请重新登录', '提示', {
     confirmButtonText: '确定',
     showClose: false,
     showCancelButton: false,
     type: 'warning'
    }).then(() => {
     clearTimeout(timer)
     reload()
    })
    timer = setTimeout(reload, 1000)
   }
   const errMsg = res.msg || '服务器返回错误'
   popupMsg(errMsg)
   return Promise.reject(errMsg)
  }
  return res
 },
 error => {
  // 超时
  if (error.message.includes('timeout')) {
   const errMsg = '网络请求超时, 请稍后重试'
   popupMsg(errMsg)
   cancel(errMsg)
  }
 }
)
function reload() {
 window.location.href = `${window.location.origin}/#/login`
 window.location.reload()
}
function popupMsg(msg, sec = 5000) {
 Message({
  message: msg,
  type: 'error',
  duration: sec
 })
}
export default service

在封装的过程中处理了 网络请求超时 、 下载表数据时后端直接返回二进制文件的情况 、 登录失效后取消后续接口请求 。

在开发后台管理系统项目时,基本都会用到Vuex。在实际的开发过程中通常会按功能进行分 module ,在 xx.vue 文件中直接通过 mapActions 来注入带副作用的方法。

// store/common.js
import service from '../services'
const actions = {
 async login(data) {
  const res = await service.login(data)
  return Promise.resolve(res)
 }
}
export default {
 namespaced: true,
 state: {},
 getters: {},
 mutations: {},
 actions
}

其实在上面的 apiFunc 方法中是可以直接调用返回结果,为什么在这里还多此一举呢?是因为有些时候一个接口的参数需要加工处理,在每个页面处理明显代码冗余,修改不方便,同时也会出现获取同样的数据但是不同的页面后端给到的是不同的接口,这里就可以做到根据参数来明确需要哪个接口。

在封装的 action 中,有些时候是不需要返回数据(Promise),因为完全可以整个页面的数据状态全部放在state中,接收到数据后直接通过 commit 一个 mutation 来修改 state ,在页面中直接把所有的数通过 mapState 或者直接 this.$store.state.xx 来访问。如果想要绑定state中的状态到 v-model ,可以在 computed 中定义 get 和 set 来实现,例如:

export default {
 computed: {
  dateType: {
   get() {
    return this.$store.state.device.dateType
   },
   set(val) {
    // 一些处理,比如根据日、周、月来动态改变`el-datep-icker`的配置
   }
  }
 }
}

在项目中不建议把页面中的所有状态全部放在vuex中处理,除了一些全局状态和一些组件之间具有联动效应的。因为在当前路由切换到其它路由, vuex中 state 的数据是没有被重置的,再切回来会发现原有的数据并没有变化等问题。而且一旦在定义 state 时嵌套太多,重置就很麻烦了。

还有一个问题在使用 echarts 时,根据一些筛选来动态改变图表绘制时,会发现从 mapState 和 getters 中并不能获取到最新的数据,还得手动写一长串的 this.$store.state.moduleA.moduleB.xxx.state ,当然我们也可以使用vuex提供的便捷映射方法 const { mapState } = createNamespacedHelper('some/nested/module') ,但是有一个问题是一旦同一个页面引用的 module 很多,就涉及到取多个不同的别名问题了。

在项目中使用方式如下:

import { mapActions } from 'vuex'
import apiFunc from '../services'

export default {
 methods: {
  ...mapActions('common', [
   'login'
  ]),
  async onLogin() {
   const params = {}
   const res = await apiFunc.login(params)
  }
 }
}

注意在使用 async/await 时如果外层的错误没有捕捉到,最好加一层 try...catch... 。

相关文章

  • 浅析Vue自定义组件的v-model

    浅析Vue自定义组件的v-model

    这篇文章主要介绍了Vue之彻底理解自定义组件的v-model的相关知识 ,需要的朋友可以参考下的相关资料
    2017-11-11
  • vue-router路由懒加载及实现方式

    vue-router路由懒加载及实现方式

    这篇文章主要介绍了vue-router路由懒加载及实现方式,路由懒加载的主要作用是将 路由对应的组件打包成一个个的js代码块,只有在这个路由被访问到的时候,才会加载对应组件的代码块,需要的朋友可以参考下
    2022-12-12
  • Vue3中插槽(slot)的全部使用方法

    Vue3中插槽(slot)的全部使用方法

    这篇文章主要介绍了Vue3中插槽(slot)的全部使用方法,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-08-08
  • 使用 Vue3 实现文章目录功能

    使用 Vue3 实现文章目录功能

    本文给大家分享如何使用vue3实现文章目录功能,特色功能主要是自动高亮选中当前正在阅读的章节,自动展开当前正在阅读的章节的子标题,并隐藏其他章节的子标题,代码简单易懂,感兴趣的朋友跟随小编一起看看吧
    2022-03-03
  • vue.js实现点击图标放大离开时缩小的代码

    vue.js实现点击图标放大离开时缩小的代码

    这篇文章主要介绍了vue.js实现点击图标放大离开时缩小,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-01-01
  • vue-cli开发环境实现跨域请求的方法

    vue-cli开发环境实现跨域请求的方法

    本篇文章主要介绍了vue-cli开发环境实现跨域请求的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-04-04
  • vue 实现单选框设置默认选中值

    vue 实现单选框设置默认选中值

    今天小编就为大家分享一篇vue 实现单选框设置默认选中值,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-11-11
  • Vue实现一个无限加载列表功能

    Vue实现一个无限加载列表功能

    这篇文章主要介绍了Vue实现一个无限加载列表功能,需要的朋友可以参考下
    2018-11-11
  • ruoyi-vue3 集成aj-captcha实现滑块、文字点选验证码功能

    ruoyi-vue3 集成aj-captcha实现滑块、文字点选验证码功能

    这篇文章主要介绍了 ruoyi-vue3 集成aj-captcha实现滑块、文字点选验证码,本文基于后端RuoYi-Vue 3.8.7 和 前端 RuoYi-Vue3 3.8.7,集成以AJ-Captcha文字点选验证码为例,不需要键盘手动输入,极大优化了传统验证码用户体验不佳的问题,感兴趣的朋友一起看看吧
    2023-12-12
  • 如何在vue3中同时使用tsx与setup语法糖

    如何在vue3中同时使用tsx与setup语法糖

    这篇文章主要介绍了如何在vue3中同时使用tsx与setup语法糖,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下
    2022-09-09

最新评论