vue项目(通用方法+axios自定义+http请求统一管理绑定+vue.config.js别名alias配置)
一般项目中会出现大量http方法和公用JS方法,在使用的时候每个页面都会出现大量 import { } from '../../。。js' ,项目迭代或者设计图修改之后就会有所变动需要重新引入,经常出现路径问题,此处大概讲一下 路径别名与axios重写与通用方法和正则的统一导入与引用,欢迎交流
目录
1、vue.config.js别名配置与使用
新建vue-cli3项目中默认是没有vue.config.js,自己在根目录新建。项目默认会定义 @ 代表 src目录
下面是个人项目中部分配置,还包括svg使用类名与组件引入类似于element-ui的icon引入设置,文件压缩等配置,可以参照vue-admin-template,后面项目空了再发一下一下配置,包括npm包与组件使用,代码eslint统一规范
//根目录 vue.config.js
'use strict'
const path = require('path')
// 完整绝对路径
let resolve = (dir)=> path.join(__dirname, dir)
const defaultSettings = require('./src/config/settings.js')
module.exports = {
runtimeCompiler: true,
productionSourceMap: false,
// assetsDir 随便定义,为public即打包之后除了index.html其他资源存在public目录中
// assetsDir: 'public',
configureWebpack: config => {
// 项目名称,不同页面的名称在路由守卫设置即可
config.name = defaultSettings.title || '通行管理系统'
// 生产环境清除开发打印与debugger
if (process.env.NODE_ENV === 'production') {
config.optimization.minimizer[0].options.terserOptions.compress.warnings = false
config.optimization.minimizer[0].options.terserOptions.compress.drop_console = true
config.optimization.minimizer[0].options.terserOptions.compress.drop_debugger = true
config.optimization.minimizer[0].options.terserOptions.compress.pure_funcs = [
'console.log'
]
}
},
// 别名设置 自定义
chainWebpack(config) {
config.resolve.alias
.set('@', resolve('src'))
.set('style', resolve('src/assets/scss'))
.set('com', resolve('src/comJs'))
.set('@img', resolve('src/assets/image'))
},
// 开发配置
devServer: {
port: process.env.VUE_APP_PORT || '9527',
open: true,
// eslint 配置,觉得问题多直接设置成false,重新run即可
overlay: {
warnings: true,
errors: true
},
// 代理
proxy: {
'^/disease': {
target: 'https://view.inews.qq.com/',
changeOrigin: true,
ws: true,
pathRewrite: {
'^/disease': '' //路径重写
}
}
}
}
}
上面配置中设置了 style === src/assets/scss; @img === src/assets/image,相信这两个目录是项目中最常用到的部分,以前项目未重视,页面充斥着大量的 ../../../等等,尤其是在scss文件 import或者设置图片背景时候最容易出现路径问题,并且使用相对路径引入还显得比较low,在这里设置了别名再也不用担心路径带来的额外工作量,下面说下使用
1、script中直接 使用 import * as com from 'com/com' 这里com就指代src目录下的comJs的路径
2、style使用 scss中引入 @import '~style/app.scss';等于引入src/assets/scss/app.scss的资源;css中引入背景:background: url(~@img/m.jpg);
3、template中使用 <img src="~@img/m.jpg" alt="" hidden ref="imgs" />
避免出现一些问题 除了JS引入之外最好前面添加 ~
2、通用方法全局使用(自定义插件)
主要是将一些通用方法或者正则校验规则与http请求统一批量挂载到Vue.prototype,组件中可以直接this.直接调用,避免了大量的import {} from '..'引入操作,尤其是配置eslint之后出现变动会有大量报错之类
1.直接在src目录中新建plugin目录 创建index.js文件,作为作为项目公共方法与请求的入口,统一管理
如上一篇文章message重写了message.js,多数操作是将message.js引入main.js,再挂到prototype上面,如果此类方法增多就会显得很臃肿,因此单独plugin模块管理还是有必要的,下面呢直接上代码;
// plugn/index.js
// 路径com就是上面的别名设置
import { message } from 'com/resetMessage'
const install = Vue => {
if (install.installed) return false
// 添加到Vue的原型链上
Object.defineProperties(Vue.prototype, {
$message: { value: message }
})
install.installed = true
}
export default install
// main.js
// 导入自定义插件
import plugin from '@/plugin'
Vue.use(plugin)
// 此时所有组件均可直接使用 this.$message.success()
上面代码中既然能引入message.js,其他公共类方法亦可直接引入挂载,如项目中一般会用到大量公共方法,一般存放在 com.js中,类似于下面的方法
// com.js
import moment from 'moment'
/**
* @description:使用moment将任意时间转化为标准格式
* @param {参数需要格式化时间,必传} time
* @param {格式化标准,'YYYY-DD-MM HH:mm:ss'} format
* @return {*}
*/
export const formatTime = (time, format) => {
if (!arguments.length) return ''
if (!format) format = 'YYYY-DD-MM HH:mm:ss'
const timer = moment(time).format(format)
return timer
}
一般公共类的方法在组件中常规用法就是 import {formatTime} from ;;;;;用一次引入一次较为繁琐,参照上面message.js,也可以直接引入
// plugin/index.js
import * as com from 'com/com'
.....
const install = Vue => {
.....
Object.defineProperties(Vue.prototype, {
.....
$com: { value: com }
})
install.installed = true
}
export default install
// 组件内就能直接使用 this.$com.formatTime() 进行调用,dom中直接 $com.xxx;但是其他JS文件中无this,只能使用import引入之后单个使用,当然这种情况极少
稍微补充点,不仅仅是公共类方法,后台管理类项目中有大量的表单填写与修改,字段不多但是界面与弹窗较多,表单正则也就十几条,也可以考虑单独存放一个JS文件中统一管理
无论是element-ui还是vue-ant或者是iview之类UI框架都能直接使用,代码如下:
// com/verify.js
/**
* 验证手机号码是否正确
* @param tel
* @returns {boolean}
*/
export const isTel = tel => /^1[3|4|5|8][0-9]\d{4,8}$/.test(tel)
export const regTel = /^1[3|4|5|8][0-9]\d{4,8}$/
// 如上校验结果与正则regTel
// plugin/index.js
import * as verify from 'com/verify'
......
const install = Vue => {
.....
Object.defineProperties(Vue.prototype, {
$valid: { value: verify },
.....
})
install.installed = true
}
export default install
// 组件内使用
console.log(this.$valid.isTel('1000')) 返回false
// 以element-ui为例,一般表单中会有rules,可如下使用
rules: {
phoneNumber: [
{ required: true, message: '手机号码不能为空', trigger: 'blur,change' },
{ pattern: this.$valid.regTel, message: '请输入正确手机号码' }
],
genderCode: [
{ required: true, message: '性别不能为空', trigger: 'blur,change' }
]
}
// 此前项目没考虑这个,这次新的考虑添加,简单测试下
// data:{ return(){ isBool:this.$valid.isTel('1000') } }能正常使用,有问题欢迎交流
3、axios自定义
// com/api.js
import axios from 'axios'
import { message } from 'com/resetMessage'
// import store from '@/store'
export const localIp = process.env.VUE_APP_BASE_API
// .env.development中配置开发环境的IP, baseUrl为获取当前web部署环境的ip,端口不变不需要额外配置
export const baseUrl = port => {
if (!port) {
port = '9527'
}
let hostname = window.location.hostname
let origin = 'http://' + hostname + ':' + port
let url = ''
url =
process.env.NODE_ENV === 'development'
? 'http://' + localIp + ':' + port
: origin
return url
}
const service = axios.create({
baseURL: baseUrl(),
// withCredentials: true, // send cookies when cross-domain requests
timeout: 5000 // request timeout
})
let Authorization = getToken('Authorization')
service.interceptors.request.use(
config => {
// 项目中的token校验
if (Authorization) {
config.headers['Authorization'] = Authorization
return config
}
return config
},
error => {
Promise.reject(error)
}
)
service.interceptors.response.use(
response => {
const res = response.data
// 下面根据项目具体code统一处理
if (!res.success) {
message({
message: res.msg || 'Error',
type: 'error',
duration: 1000
})
Promise.reject(res)
} else {
return res
}
},
error => {
message({
message: error,
type: 'error' || '网络错误',
duration: 1000,
onClose: () => {
Promise.reject(error)
}
})
}
)
export default service
使用:import request from 'comjs/api'
request({ url: userUrl.login, data, method: 'post' }).then(res=>{}).catch(e=>{})
或者直接在main.js中引入挂载到prototype上面,全局使用 this.$request()调用。在上面能看到无论是公共类方法或者校验都能直接在 plugin/index.js中挂载,作为统一入口,当然http请求也不例外,统一管理
4、http请求统一管理绑定
下面先看一下个人项目定义的目录
如上图所示,项目中将http请求分两个部分:constant中存放不同模块的静态url,modules中分别引入对应模块的静态url,定义使用request方法;src/api/index.js 则是读取modules目录下的所有js文件(统一批量注册vue全局公共组件此处方法类似,看过的话应该能更好理解),批量引入并在plugin/index.js中挂载,任意组件均可使用
下面分别看下各个文件代码
// api/constant/user.js
// 存放静态url,方便管理
export const login = '/UserController/login' // 登录
export const handleObj = '/ImgObjController/obj' // 操作
// api/modules/user.js
// 一般存放登录、登出、个人信息或者权限之类公共接口
import request from 'comJs/api'
import * as userUrl from '@/api/constant/user'
// 登录
export const login = data => {
return request({ url: userUrl.login, data, method: 'post' })
}
modules中包含多个文件,多人开发互不干扰(明天有时间就分享一下多人开发代码格式问题),个人感觉分块维护较为方便;下面看下 api/index.js文件
// api/index.js
// 文件夹下嵌套js文件,进行驼峰命名转换
let _result = {}
const camelCaseChange = (str, separator = '/') =>
str.replace(new RegExp(`${separator}(\\w)`, 'g'), str =>
str.slice(1).toUpperCase()
)
// 读取modules中的http请求
const context = require.context('./modules', true, /\.js$/)
context.keys().map(item => {
const k = camelCaseChange(item.match(/\.\/(\S*)\.js$/)[1])
// console.log('获取数据', item.match(/\.\/(\S*)\.js$/))
_result[k] = context(item)
})
export default _result
最后一步就是将 api/index.js文件读取到module对象 {blog: Module, user: Module} 挂载到vue.prototype上面方便全局调用
// plugs/index.js
// 下面api 相当于 {blogs:module,user:module}
......
import api from '@/api'
const install = Vue => {
.....
Object.defineProperties(Vue.prototype, {
.....
$api: { value: api },
})
install.installed = true
}
export default install
// 此时挂载到全局之后,在所有组件中都不需要再次 Import请求名称函数
// 组件内使用,可以链式调用如下
this.$api.user.login(params).then(res=>{})
this.$api.blogs.getList(params).then(res=>{})
// 也可使用async和await
async Login(){
const data = await this.$api.user.login(params)
console.log(data)
}
更多推荐
所有评论(0)