(注:下面以vue项目为例子)
一. 一般项目中api的调用方式
1. 目录结构
|── src
|── |── utils (工具方法文件夹)
|── |── |── http.js (封装的请求方法)
|── |── views (页面文件夹)
|── |── |── device (可以理解为一级菜单)
|── |── |── |── board(可以理解为二级菜单页面)
|── |── |── |── |── index.vue
2. 常见的api调用形式
第一步: 一般都会在http.js中封装好axios的get,post等方法,利用拦截器统一处理请求前和响应后的逻辑。
将http这个方法绑定在vue实例上,Vue.prototype.$http = http
第二步: 在上面index.vue中调用
<script>
export default {
data () {
return {
data: ""
}
},
methods: {
async getData () {
const { data } = await this.$https.get("/url/test")
this.data = data
}
}
</script>
3. 问题
(1) 我们传入的后端地址"/url/test",如果要继续用到,我们还是要重复写一遍 this.$https.get("/url/test");
(2) 当页面中有大量的接口调用就会出现接口地址不易管理的情况,这个能否新建一个文件统一管理?
二. 理想项目中的api组织结构(优化1)
1. 目录结构
我们应该有一个api文件夹,存放当前对应模块的接口
board.js 中是这样定义的
import { http } form '@/utils/http.js'
export default {
getBoardData () {
return http.get("/url/test")
}
}
|── src
|── |── utils
|── |── |── http.js
|── |── views
|── |── |── device (可以理解为一级菜单)
|── |── |── |── board(可以理解为二级菜单页面)
|── |── |── |── |── index.vue
|── |── api
|── |── |── common (存放公共的方法)
|── |── |── |── index.js
|── |── |── device (一级菜单名)
|── |── |── |── board.js(二级菜单页面名字)
|── |── |── index.js
2. 调用
在 board的模块下的index.vue中使用
<script>
import boardApi from "@/api/device/board.js"
export default {
data () {
return {
data: ""
}
},
methods: {
async getData () {
const { data } = await boardApi.getBoardData()
this.data = datad
}
}
<script>
3. 问题
(1) 每次都要import, 能不能用一个全局变量去加载这些接口文件,$service.getData()的形式
三 . 理想项目中的api组织结构(优化2)
1. webpack的require.context
通过 require.context() 函数来创建自己的 context。
可以给这个函数传入三个参数:一个要搜索的目录,一个标记表示是否还搜索其子目录, 以及一个匹配文件的正则表达式。
// 找出当前目录下包括子目录所有以.js结尾的文件
const files = require.context("./",true, "\.js$")
所以我们可以利用webpack的require.context得到我们的文件结构
2. 在api文件夹的index.js
|── src
|── |── utils
|── |── |── http.js
|── |── views
|── |── |── device (可以理解为一级菜单)
|── |── |── |── board(可以理解为二级菜单页面)
|── |── |── |── |── index.vue
|── |── api
|── |── |── common (存放公共的方法)
|── |── |── |── index.js
|── |── |── device (一级菜单名)
|── |── |── |── board.js(二级菜单页面名字)
|── |── |── index.js
// api文件的index.js
const files = require.context('./', true, /\.js$/)
const commonApis = {}
files.keys().forEach(key => { //require.context的 keys() 返回一个文件路径匹配数组
if (key === './index.js') {
return false
}
const arr = key.match(/\.\/(.*)\/(.*).js)
/**
* commonApis的结构
* {
* device: {
* getBoardData () {}
* }
*
* }
*/
commonApis[arr[1]] = { ...commonApis[arr[1]], ...files(key).default }
})
export default commonApis
3.调用
//commonApis的结构
{
device: { // 一级菜单名
getBoardData () {}
}
}
以上我们得到了一个commonApis的对象,我们得把它绑定在一个变量上,比如$service
所以需要在 vue.config.js 定义
const webpack = require('webpack')
const path = require('path')
function resolve (dir) {
return path.join(__dirname, dir)
}
module.exports = {
// 调整 webpack 配置(放置plugins等)
configureWebpack: {
resolve: {
alias: { // 给路径起别名
service: resolve('src/api/index.js')
}
},
plugins: [
new webpack.ProvidePlugin({ // 自动加载模块的插件
$service: ['service', 'default'],
})
]
}
}
这样就可以在board中index.vue中这样调用
<script>
export default {
data () {
return {
data: ""
}
},
methods: {
async getData () {
const { data } = await $service.device.getBoardData()
this.data = data
}
}
</script>