目录

1、vue.config.js别名配置与使用

2、通用方法全局使用(自定义插件)

3、axios自定义

4、http请求统一管理绑定


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)
}

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐