溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

發(fā)布時間:2020-09-15 02:06:53 來源:腳本之家 閱讀:498 作者:不愛貞子愛爽子 欄目:web開發(fā)

新建項目的時候創(chuàng)建合理的目錄結(jié)構(gòu)便于后期的維護是很重要

環(huán)境:vue、webpack

目錄結(jié)構(gòu):

項目子目錄結(jié)構(gòu)

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

子目錄結(jié)構(gòu)都差不多,主要目錄是在src下面操作

src目錄結(jié)構(gòu)

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

src/common 目錄

主要用來存放公共的文件

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

src/components

主要用來存放公共的組件

src/config

用來存放配置文件,文件目錄如下

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

src/config/index.js 配置目錄入口文件

import api from './website'

// 當(dāng)前平臺
export const HOST_PLATFORM = 'WEB'
// 當(dāng)前環(huán)境
export const NODE_ENV = process.env.NODE_ENV || 'prod'

// 是否開啟監(jiān)控
export const MONITOR_ENABLE = true

// 路由默認配置
export const ROUTER_DEFAULT_CONFIG = {
 // mode: 'history',
 waitForData: true,
 transitionOnLoad: true
}

// axios 默認配置
export const AXIOS_DEFAULT_CONFIG = {
 timeout: 20000,
 maxContentLength: 2000,
 headers: {}
}

// vuex 默認配置
export const VUEX_DEFAULT_CONFIG = {
 strict: process.env.NODE_ENV !== 'production'
}

// API 默認配置
export const API_DEFAULT_CONFIG = {
 baseURL: api,
 // 圖標(biāo)地址
 imgUrl: `${api}/api/system/icon.do?name=`,
 // 菜單圖標(biāo)地址
 menuImgUrl: `${api}/`,
 dicomUrl: `${api}/testDICOM/`,
 // 請求參數(shù)格式 json/form-data
 isJSON: true,
 // 請求加載效果, 支持element-ui所有參數(shù)配置
 loading: { text: '加載中' },
 // 是否開啟mock
 mock: false,
 // 是否開啟debug
 debug: false,
 // 定義全局變量
 ippid: 'test'
}

export const CONSOLE_REQUEST_ENABLE = true // 開啟請求參數(shù)打印
export const CONSOLE_RESPONSE_ENABLE = false // 開啟響應(yīng)參數(shù)打印
export const CONSOLE_ROUTER_ENABLE = false // 打印路由信息
export const CONSOLE_MONITOR_ENABLE = true // 監(jiān)控記錄打印

src/config/website.js 動態(tài)配置ip文件

/**
 * 動態(tài)匹配api接口地址
 */
const website = [
 {
  web: 'localhost:9000',
  api: '//192.168.0.170:8080/xhhms',
  env: 'dev'
 },
 {
  web: '127.0.0.1:8000',
  api: '//192.168.0.149:8080/xhhms',
  env: 'dev'
 }
]

let matchApi = website.filter(item => new RegExp(item.web).test(location.href))

if (matchApi.length > 1) {
 console.error(`${location.href}: 該站點映射了多個api地址${matchApi.map(item => item.api).join(',')},默認選取第一個匹配項`)
}

export default matchApi[0].api

src/config/interceptors目錄

攔截器配置

src/config/interceptors/axios.js

import router from 'Plugins/router'
import { CONSOLE_REQUEST_ENABLE, CONSOLE_RESPONSE_ENABLE } from '../index.js'
import { Toast, Indicator } from 'mint-ui'
import store from 'Store'

import Qs from 'qs'
/**
 * 請求攔截器(成功)
 * @param {object} request 請求對象
 * @return {object} request 處理后的請求對象
 */
export function requestSuccessFunc(request) {
 CONSOLE_REQUEST_ENABLE &&
 console.info('requestInterceptorFunc', `url: ${request.url}`, request)
 // 自定義請求攔截邏輯,可以處理權(quán)限,請求發(fā)送監(jiān)控等
 // console.log(request.url)
 // if (localStorage.getItem('token') === null && request.url.indexOf('login') === -1) {
 //  console.log('[*] 當(dāng)前用戶沒有登錄?。?)
 //  router.push('/login')
 //  return false
 // }
 // 登錄token攜帶
 request.headers['X-AUTH-TOKEN'] = localStorage.getItem('token')

 // 兼容性寫法,如果request里邊沒得site_code 就用全局site_code
 let publicParams = {
  orgCode: sessionStorage.getItem('orgCode'),
  menuId: sessionStorage.getItem('currentMenuId')
 }

 /**
  * @author wucheshi
  * @time 2018-08-13
  * @description 需求變動,網(wǎng)站code從本地siteCodeList 這個字段來
 */
 let siteCodeList = sessionStorage.getItem('siteCodeList')
 // !request.data.site_code && (publicParams = Object.assign({ site_code: store.state.currentSite.code }, publicParams))
 !request.data.site_code && !request.noSiteCode && (publicParams = Object.assign({ site_code: siteCodeList }, publicParams))

 /**
  * @author wucheshi
  * @time 2018-08-13
  * @description 單表操作接口不需要傳遞sitecode
 */
 // 兼容單表操作傳遞site_code
 // if (request.data.condition && !request.noSiteCode) {
 //  console.log(siteCodeList, 11111)
 //  if (request.data.condition.findIndex(item => item.name === 'site_code') === -1) {
 //   request.data.condition.push({ name: 'site_code', value: siteCodeList })
 //  } else {
 //   request.data.condition.find(item => item.name === 'site_code').value = siteCodeList
 //  }
 // }

 let newData
 // 判斷是否是formdata類型
 if (Object.prototype.toString.call(request.data) === '[object FormData]') {
  // 合并formdata格式公共參數(shù)
  Object.keys(publicParams).forEach(key => {
   request.data.append(key, publicParams[key])
  })
  newData = request.data
 } else {
  // 合并公共參數(shù)
  newData = Object.assign(request.data, publicParams)

  // 判斷是否采用json格式提交參數(shù)
  !request.isJSON && (newData = Qs.stringify(newData))
 }

 // 不同提交參數(shù)方式給不同的字段賦值
 if (request.method.toUpperCase() === 'POST') {
  request.data = newData
 } else if (request.method.toUpperCase() === 'GET') {
  request.params = newData
 }

 // 加載效果
 request.loading && Indicator.open(request.loading)

 // 輸出請求數(shù)據(jù)
 CONSOLE_REQUEST_ENABLE &&
 console.info(`%c
請求接口地址:${request.url}

請求接口名稱:${request.desc}

請求參數(shù)JSON: 

${JSON.stringify(request.data, '', 2)}

`, 'color: #f60')

 return request
}

/**
 * 請求攔截器(失敗)
 * @param {object} requestError 請求報錯對象
 * @return {object} 返回promise對象
 */
export function requestFailFunc(requestError) {
 // 自定義發(fā)送請求失敗邏輯,斷網(wǎng),請求發(fā)送監(jiān)控等
 return Promise.reject(requestError)
}
// 你就是個sx
/**
 * 響應(yīng)攔截器(成功)
 * @param {object} responseObj 響應(yīng)對象
 */
export function responseSuccessFunc(responseObj) {
 // 自定義響應(yīng)成功邏輯,全局攔截接口,根據(jù)不同業(yè)務(wù)做不同處理,響應(yīng)成功監(jiān)控等
 // console.log(typeof (responseObj.data))
 // // 判斷string是否包含 java字段 說明error
 // if (typeof (responseObj.data) === 'string' || responseObj.data.indexOf('java') !== -1) {
 //  console.log('[*] token錯誤')
 //  this.$router.push('/login')
 // }
 // 加載效果
 Indicator.close()
 // 響應(yīng)對象
 let resData =
  typeof responseObj.data === 'object'
   ? responseObj.data
   : JSON.parse(responseObj.data)
 let { status, message } = resData

 // 輸出響應(yīng)體
 CONSOLE_RESPONSE_ENABLE && console.info(responseObj)
 // 輸出返回JSON數(shù)據(jù)
 CONSOLE_RESPONSE_ENABLE &&
  console.info(`%c
響應(yīng)接口地址: ${responseObj.config.url}

響應(yīng)接口描述: ${responseObj.config.desc}

響應(yīng)數(shù)據(jù)JSON:

${JSON.stringify(resData, '', 2)}
  `, 'color: blue')

 // 自定義處理業(yè)務(wù)邏輯
 if (responseObj.config.customErrorHandle) {
  return resData
 }

 // 統(tǒng)一邏輯處理
 switch (+status) {
  case 0: // 常規(guī)錯誤
   Toast(message)
   break
  case 1: // 如果業(yè)務(wù)成功,直接進成功回調(diào)
   return resData
  case 401: // 登錄失效
   store.commit('DELETE_USER_INFO')
   router.push({ path: '/login', redirect: router.app._route.fullPath })
   Toast(message)
   break
  default:
   // 業(yè)務(wù)中還會有一些特殊 code 邏輯,我們可以在這里做統(tǒng)一處理,也可以下方它們到業(yè)務(wù)層
   // !responseObj.config.noShowDefaultError && GLOBAL.vbus.$emit('global.$dialog.show', resData.msg);
   return Promise.reject(resData)
 }
}

/**
 * 響應(yīng)攔截器(失敗)
 * @param {object} responseError 響應(yīng)報錯對象
 * @return {object} 返回promise對象
 */
export function responseFailFunc(responseError) {
 // 響應(yīng)失敗,可根據(jù) responseError.message 和 responseError.response.status 來做監(jiān)控處理
 // ...
 // 加載效果
 Indicator.close()
 // 錯誤碼處理
 // console.log(responseError.response)
 if (typeof (responseError.response) === 'undefined') {
  return false
 }
 switch (responseError.response.status) {
  case 401:
   console.error('401錯誤')
   store.commit('DELETE_USER_INFO')
   router.push({ path: '/login', redirect: router.app._route.fullPath })
   store.state.user.username && Toast('登錄超時')
   break
  case 403:
   console.error('403錯誤')
   router.push({ path: '/403' })
   break
  case 500:
   console.error('500錯誤')
   router.push({ path: '/500' })
   break
 }
 return Promise.reject(responseError)
}

src/config/interceptors/index.js

import {requestSuccessFunc, requestFailFunc, responseSuccessFunc, responseFailFunc} from './axios'
import {routerBeforeEachFunc} from './router'

export default {
 requestSuccessFunc,
 requestFailFunc,
 responseSuccessFunc,
 responseFailFunc,
 routerBeforeEachFunc
}

src/config/interceptors/router.js

/**
 * 路由beforeach攔截器
 */

import {CONSOLE_ROUTER_ENABLE} from '../index'

export function routerBeforeEachFunc (to, from, next) {
 // 打印路由數(shù)據(jù)
 CONSOLE_ROUTER_ENABLE && console.info(`%c
路由to: 

fullPath: ${to.fullPath},
query: ${JSON.stringify(to.query, '', 2)},
meta: ${JSON.stringify(to.meta, '', 2)}

路由from: 

fullPath: ${from.fullPath}

 `, 'color: green;font-weight: bold;')

 // 登錄狀態(tài)驗證
 if (to.meta.requireLogin) {
  (localStorage.getItem('token')) ? next() : next({path: '/login', query: { redirect: to.fullPath }})
  return
 }

 // 路由重定向
 // if (to.query.route) {
 //  let newQuery = Object.assign({}, to.query)
 //  delete newQuery.route
 //  next({
 //   path: `${to.query.route.indexOf('/') === 0 ? '' : '/'}${to.query.route}`,
 //   query: newQuery
 //  })
 //  return
 // }
 // console.log(to, from)

 // 防止死循環(huán)
 if (to.fullPath === from.fullPath) return

 // 404錯誤
 if (!to.name) {
  next('/404')
  return
 }

 next()
}

src/locale目錄

國際化配置,這個百度一下就行

src/mixin目錄

引入配置文件,定義部分全局變量,名字自己定義

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

src/mixin/index.js

import Vue from 'vue'

import { API_DEFAULT_CONFIG } from 'Config'

Vue.mixin({
 computed: {
  // 圖片根地址
  imgUrl () {
   return API_DEFAULT_CONFIG.imgUrl
  },
  baseUrl () {
   return API_DEFAULT_CONFIG.baseURL
  },
  ippid () {
   return API_DEFAULT_CONFIG.ippid
  },
  dicomUrl () {
   return API_DEFAULT_CONFIG.dicomUrl
  }
 }
})

src/pages目錄

主要的頁面文件,目錄結(jié)構(gòu)主要按照層次結(jié)構(gòu)來分。

ex:該頁面主要跟醫(yī)生相關(guān),主要包含云搜索(cloud)、個人中心(myCenter)、工作中心(workCenter)、搜索(serach)、同理子層級也同樣區(qū)分、目錄結(jié)構(gòu)如下

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

至于公共頁面可以放在common文件目錄下,也可以擺在文件夾外面。

src/plugins目錄

也是配置文件目錄

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

src/plugins/api.js

import axios from './axios'
import _pick from 'lodash/pick'
import _assign from 'lodash/assign'
import _isEmpty from 'lodash/isEmpty'

import { assert } from 'Utils/tools'
import { API_DEFAULT_CONFIG } from 'Config'
import API_CONFIG from 'Service/api'

class MakeApi {
 constructor (options) {
  this.api = {}
  this.options = Object.assign({}, options)
  this.apiBuilder(options)
 }

 apiBuilder ({
  config = {}
 }) {
  Object.keys(config).map(namespace => {
   this._apiSingleBuilder({
    namespace,
    config: config[namespace]
   })
  })
 }
 _apiSingleBuilder ({
  namespace,
  config = {}
 }) {
  config.forEach(api => {
   const { methodsName, desc, params, method, path, mockPath } = api
   let { mock, mockBaseURL, baseURL, debug, isJSON, loading } = this.options
   let url = mock ? (mockBaseURL + mockPath) : (baseURL + path)
   debug && assert(methodsName, `${url} :接口methodsName屬性不能為空`)
   debug && assert(url.indexOf('/') === 0, `${url} :接口路徑path,首字符應(yīng)為/`)

   Object.defineProperty(this.api, methodsName, {
    value (outerParams, outerOptions) {
     let allowtParam = (outerOptions && outerOptions.allowParams) || {}
     let _data = (outerOptions && outerOptions.isFormData) ? outerParams : _isEmpty(outerParams) ? params : _pick(_assign({}, params, outerParams), Object.keys(Object.assign(params, allowtParam)))
     return axios(_assign({
      url,
      desc,
      method,
      isJSON,
      loading
     }, outerOptions, { data: _data }))
    }
   })
  })
 }
}

export default new MakeApi({
 config: API_CONFIG,
 ...API_DEFAULT_CONFIG
})['api']

src/plugins/axios.js

import axios from 'axios'
import {AXIOS_DEFAULT_CONFIG} from 'Config/index'
import {requestSuccessFunc, requestFailFunc, responseSuccessFunc, responseFailFunc} from 'Config/interceptors/axios'

let axiosInstance = {}

axiosInstance = axios.create(AXIOS_DEFAULT_CONFIG)

// 注入請求攔截
axiosInstance
 .interceptors.request.use(requestSuccessFunc, requestFailFunc)
// 注入失敗攔截
axiosInstance
 .interceptors.response.use(responseSuccessFunc, responseFailFunc)

export default axiosInstance

src/plugins/inject.js

import axios from './axios'
import api from './api'
// GLOBAL.ajax = axios
export default {
 install: (Vue, options) => {
  Vue.prototype.$api = api
  Vue.prototype.$ajax = axios
  // 需要掛載的都放在這里
 }
}

src/plugins/router.js

import Vue from 'vue'
import Router from 'vue-router'
import ROUTES from 'Routes'
import {ROUTER_DEFAULT_CONFIG} from 'Config/index'
import {routerBeforeEachFunc} from 'Config/interceptors/router'

Vue.use(Router)

// 注入默認配置和路由表
let routerInstance = new Router({
 ...ROUTER_DEFAULT_CONFIG,
 routes: ROUTES
})
// 注入攔截器
routerInstance.beforeEach(routerBeforeEachFunc)

export default routerInstance

src/router目錄

路由配置文件目錄,同理按照頁面的層次結(jié)構(gòu)來,結(jié)構(gòu)如下

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

我們來看src/router/index.js 和 src/common/index.js 即可

src/common/index.js

const routes = [
 {
  path: '/login',
  name: 'Login',
  component: () => import('Pages/login'),
  meta: {
   require: true,
   title: '登錄'
  }
 },
 {
  path: '/register',
  name: 'register',
  component: () => import('Pages/register'),
  meta: {
   require: true,
   title: '注冊'
  }
 },
 {
  path: '/404',
  name: '404',
  component: () => import('Pages/error/404.vue'),
  meta: {
   require: true,
   title: '404'
  }
 },
 {
  path: '/500',
  name: '500',
  component: () => import('Pages/error/500.vue'),
  meta: {
   require: true,
   title: '500'
  }
 },
 {
  path: '/403',
  name: '403',
  component: () => import('Pages/error/403.vue'),
  meta: {
   require: true,
   title: '403'
  }
 }
]

export default routes

src/router/index.js

import common from './common'
import doctor from './doctor'
import patient from './patient'
import test from './test'

const route = [
 {
  path: '/',
  redirect: '/login'
 },
 {
  path: '/checkrecord',
  name: 'checkrecord',
  component: () => import('Pages/checkrecord.vue'),
  meta: {
   require: true,
   title: '檢查記錄'
  }
 },
 {
  path: '/report',
  name: 'report',
  component: () => import('Pages/report.vue'),
  meta: {
   require: true,
   title: '心電圖報告'
  }
 },
 {
  path: '/opinion',
  name: 'opinion',
  component: () => import('Pages/opinion.vue'),
  meta: {
   require: true,
   title: '意見'
  }
 },
 {
  path: '/bind',
  name: 'bind',
  component: () => import('Pages/bind.vue'),
  meta: {
   require: true,
   title: '綁定'
  }
 },
 ...common,
 ...doctor,
 ...patient,
 ...test
]

export default route

把所有的路由文件掛載進去。

src/service 目錄

接口配置文件目錄,根據(jù)頁面來定義文件

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

同理我們只看src/service/api/index.js 和src/service/api/login.js、src/pages/login/index.vue以及頁面如何調(diào)用接口即可。

src/service/api/login.js

先定義好login接口

const login = [
 {
  methodsName: 'loginByPhone',  // 方法名
  method: 'POST',
  desc: '登錄',
  path: '/rest/app/login',   // 接口路徑
  mockPath: '/rest/app/login', 
  params: {   // 參數(shù)配置 這里需要注意,只有配置的這些參數(shù)才能通過接口,所以需要傳遞的參數(shù)都要在這里配置
   phone: 1,
   password: 2,
   code: 3,
   codeid: '',
   clientid: ''
  }
 },
 {
  methodsName: 'login',
  method: 'POST',
  desc: '登錄',
  path: '/rest/interfacesLoginController/login',
  mockPath: '/rest/interfacesLoginController/login',
  params: {
   username: 1,
   password: 2,
   code: 3,
   codeid: '',
   clientid: ''
  }
 },
 {
  methodsName: 'checkcode',
  method: 'POST',
  desc: '驗證提取碼',
  path: '/rest/app/medical/checksharecode',
  mockPath: '/rest/app/medical/checksharecode',
  params: {
   sharecode: '',
   id: ''
  }
 },
 {
  methodsName: 'getCode',
  method: 'POST',
  desc: '獲取驗證碼',
  path: '/rest/interRandomCodeController/gererateRandomCode',
  mockPath: '',
  params: {
  }
 },
 {
  methodsName: 'getPublicKey',
  method: 'POST',
  desc: '獲取公鑰',
  path: '/rest/interRandomCodeController/clientIdAndPublicKey',
  mockPath: '',
  params: {
  }
 }
]

export default login

src/service/api/index.js

掛載所有定義的接口文件

import login from './login'
import workcenter from './workcenter'
import detail from './detail'
import register from './register'
import doctorpc from './doctorpc'
import patientpc from './patientpc'
import checklist from './checklist'
export default {
 login,
 workcenter,
 detail,
 register,
 doctorpc,
 patientpc,
 checklist
}

src/pages/login/index.vue

this.$api.login( params).then(data => {
  
})
// 這樣調(diào)用登陸接口  this.$api.方法名(參數(shù)).then(res=>{}) 
// 方法名定義不能重名

其它目錄

這些目錄還是包含很多東西,用戶的信息保存,主體,工具函數(shù)這些,就不多說了。

Vue+webpack項目配置便于維護的目錄結(jié)構(gòu)教程詳解

對于項目的維護還是需要看重,后期維護方便也便于管理。

總結(jié)

以上所述是小編給大家?guī)淼腣ue+webpack項目配置便于維護的目錄結(jié)構(gòu)的相關(guān)知識,希望對大家有所幫助,如果大家有任何疑問歡迎給我留言,小編會及時回復(fù)大家的!

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI