Vue项目中Api的组织和返回数据处理的操作
项目中的所有Api配置放在一个文件中,便于查找和修改,Api的版本从配置文件(config.js)中读取,采用 apiPrefix+url的形式组成。
在配置文件中,Api的配置采用 Http请求方式url的方式,默认情况下 GET可以不写,请求方式统一采用大写形式,动态参数采用 :占位符的形式。
//services/api.js
exportdefault{
login:'POST/login',
logout:'/logout',
queryUser:'/user/:id'
}
然后需要一个方法在解析上面的Api配置
//services/index.js
importrequestfrom'../utils/request'
importapifrom'./api'
constgen=params=>{
leturl=params
letmethod='GET'
constparamsArr=params.split('')
if(paramsArr.length===2){
method=paramsArr[0]
url=paramsArr[1]
}
returndata=>{
returnrequest({
url,
data,
method
})
}
}
constapiFunc={}
for(constkeyinapi){
apiFunc[key]=gen(api[key])
}
exportdefaultapiFunc
上面代码中的 request是封装 axios后暴露出来的方法,代码如下:
//utils/request.js
importaxiosfrom'axios'
importstorefrom'../store'
import{apiPrefix}from'./config'
import{Message,MessageBox}from'element-ui'
letcancel
constCancelToken=axios.CancelToken
constservice=axios.create({
baseURL:apiPrefix,
timeout:3000,
cancelToken:newCancelToken(c=>cancel=c)
})
service.interceptors.response.use(
response=>{
constresType=response.config.responseType
constres=response.data
//二进制文件
if(resType&&resType!=='json'){
constfilename=response.headers['content-disposition'].split('filename=')[1]
return{
filename,
blob:res
}
}
if(res.code!==200){
//登录失效
if(res.code===401){
lettimer=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)
}
consterrMsg=res.msg||'服务器返回错误'
popupMsg(errMsg)
returnPromise.reject(errMsg)
}
returnres
},
error=>{
//超时
if(error.message.includes('timeout')){
consterrMsg='网络请求超时,请稍后重试'
popupMsg(errMsg)
cancel(errMsg)
}
}
)
functionreload(){
window.location.href=`${window.location.origin}/#/login`
window.location.reload()
}
functionpopupMsg(msg,sec=5000){
Message({
message:msg,
type:'error',
duration:sec
})
}
exportdefaultservice
在封装的过程中处理了 网络请求超时、 下载表数据时后端直接返回二进制文件的情况、 登录失效后取消后续接口请求。
在开发后台管理系统项目时,基本都会用到Vuex。在实际的开发过程中通常会按功能进行分 module,在 xx.vue文件中直接通过 mapActions来注入带副作用的方法。
//store/common.js
importservicefrom'../services'
constactions={
asynclogin(data){
constres=awaitservice.login(data)
returnPromise.resolve(res)
}
}
exportdefault{
namespaced:true,
state:{},
getters:{},
mutations:{},
actions
}
其实在上面的 apiFunc方法中是可以直接调用返回结果,为什么在这里还多此一举呢?是因为有些时候一个接口的参数需要加工处理,在每个页面处理明显代码冗余,修改不方便,同时也会出现获取同样的数据但是不同的页面后端给到的是不同的接口,这里就可以做到根据参数来明确需要哪个接口。
在封装的 action中,有些时候是不需要返回数据(Promise),因为完全可以整个页面的数据状态全部放在state中,接收到数据后直接通过 commit一个 mutation来修改 state,在页面中直接把所有的数通过 mapState或者直接 this.$store.state.xx来访问。如果想要绑定state中的状态到 v-model,可以在 computed中定义 get和 set来实现,例如:
exportdefault{
computed:{
dateType:{
get(){
returnthis.$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'
importapiFuncfrom'../services'
exportdefault{
methods:{
...mapActions('common',[
'login'
]),
asynconLogin(){
constparams={}
constres=awaitapiFunc.login(params)
}
}
}
注意在使用 async/await时如果外层的错误没有捕捉到,最好加一层 try...catch...。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。