1. 接口模块处理 1.1 axios二次封装 这里封装的依据是后台传的JWT,已封装好的请跳过。 紧接着的是响应拦截器(即异常处理) 这里做的处理分别是会话已失效和登陆超时,具体的需要根据业务来作变更。 最后是导出基础请求类型封装。 其中给get请求加上时间戳参数,避免从缓存中拿数据。 除了基础请求类型,还有很多类似下载、上传这种,需要特殊的的请求头,此时可以根据自身需求进行封装。 浏览器缓存是基于url进行缓存的,如果页面允许缓存,则在一定时间内(缓存时效时间前)再次访问相同的URL,浏览器就不会再次发送请求到服务器端,而是直接从缓存中获取指定资源。 1.2 请求按模块合并 utils/api/index.js: 1.3 global.js中的处理 在global.js中引入: 写接口的时候就可以简化为: 2. Vue组件动态注册 我们写组件的时候通常需要引入另外的组件: 写小项目这么引入还好,但等项目一臃肿起来...啧啧。 这里是借助webpack,使用 require.context() 方法来创建自己的模块上下文,从而实现自动动态require组件。 这个方法需要3个参数: 在你放基础组件的文件夹根目录下新建componentRegister.js: 最后我们在main.js中 import 'components/componentRegister.js' 我们就可以随时随地使用这些基础组件,无需手动引入了。import axios from 'axios'
import router from '../router'
import {MessageBox, Message} from 'element-ui'
let loginUrl = '/login'
// 根据环境切换接口地址
axios.defaults.baseURL = process.env.VUE_APP_API
axios.defaults.headers = {'X-Requested-With': 'XMLHttpRequest'}
axios.defaults.timeout = 60000
// 请求拦截器
axios.interceptors.request.use(
config => {
if (router.history.current.path !== loginUrl) {
let token = window.sessionStorage.getItem('token')
if (token == null) {
router.replace({path: loginUrl, query: {redirect: router.currentRoute.fullPath}})
return false
} else {
config.headers['Authorization'] = 'JWT ' + token
}
}
return config
}, error => {
Message.warning(error)
return Promise.reject(error)
})
axios.interceptors.response.use(
response => {
return response.data
}, error => {
if (error.response !== undefined) {
switch (error.response.status) {
case 400:
MessageBox.alert(error.response.data)
break
case 401:
if (window.sessionStorage.getItem('out') === null) {
window.sessionStorage.setItem('out', 1)
MessageBox.confirm('会话已失效! 请重新登录', '提示', {confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning'}).then(() => {
router.replace({path: loginUrl, query: {redirect: router.currentRoute.fullPath}})
}).catch(action => {
window.sessionStorage.clear()
window.localStorage.clear()
})
}
break
case 402:
MessageBox.confirm('登陆超时 !', '提示', {confirmButtonText: '重新登录', cancelButtonText: '取消', type: 'warning'}).then(() => {
router.replace({path: loginUrl, query: {redirect: router.currentRoute.fullPath}})
})
break
case 403:
MessageBox.alert('没有权限!')
break
// ...忽略
default:
MessageBox.alert(`连接错误${error.response.status}`)
}
return Promise.resolve(error.response)
}
return Promise.resolve(error)
})
export default {
get (url, param) {
if (param !== undefined) {
Object.assign(param, {_t: (new Date()).getTime()})
} else {
param = {_t: (new Date()).getTime()}
}
return axios({method: 'get', url, params: param})
},
// 不常更新的数据用这个
getData (url, param) {
return axios({method: 'get', url, params: param})
},
post (url, param, config) {
return axios.post(url, param, config)
},
put: axios.put,
_delete: axios.delete
}
模块的请求:import http from '@/utils/request'
export default {
A (param) { return http.get('/api/', param) },
B (param) { return http.post('/api/', param) }
C (param) { return http.put('/api/', param) },
D (param) { return http._delete('/api/', {data: param}) },
}
import http from '@/utils/request'
import account from './account'
// 忽略...
const api = Object.assign({}, http, account, \*...其它模块*\)
export default api
import Vue from 'vue'
import api from './api/index'
// 略...
const errorHandler = (error, vm) => {
console.error(vm)
console.error(error)
}
Vue.config.errorHandler = errorHandler
export default {
install (Vue) {
// 添加组件
// 添加过滤器
})
// 全局报错处理
Vue.prototype.$throw = (error) => errorHandler(error, this)
Vue.prototype.$http = api
// 其它配置
}
}
async getData () {
const params = {/*...key : value...*/}
let res = await this.$http.A(params)
res.code === 4000 ? (this.aSata = res.data) : this.$message.warning(res.msg)
}
<template>
<BaseInput v-model="searchText" @keydown.enter="search"/>
<BaseButton @click="search">
<BaseIcon name="search"/>
</BaseButton>
</template>
<script>
import BaseButton from './baseButton'
import BaseIcon from './baseIcon'
import BaseInput from './baseInput'
export default {
components: { BaseButton, BaseIcon, BaseInput }
}
</script>
import Vue from 'vue'
/**
* 首字母大写
* @param str 字符串
* @example heheHaha
* @return {string} HeheHaha
*/
function capitalizeFirstLetter (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
/**
* 对符合'xx/xx.vue'组件格式的组件取组件名
* @param str fileName
* @example abc/bcd/def/basicTable.vue
* @return {string} BasicTable
*/
function validateFileName (str) {
return /^\S+\.vue$/.test(str) &&
str.replace(/^\S+\/(\w+)\.vue$/, (rs, $1) => capitalizeFirstLetter($1))
}
const requireComponent = require.context('./', true, /\.vue$/)
// 找到组件文件夹下以.vue命名的文件,如果文件名为index,那么取组件中的name作为注册的组件名
requireComponent.keys().forEach(filePath => {
const componentConfig = requireComponent(filePath)
const fileName = validateFileName(filePath)
const componentName = fileName.toLowerCase() === 'index'
? capitalizeFirstLetter(componentConfig.default.name)
: fileName
Vue.component(componentName, componentConfig.default || componentConfig)
})