(编辑:jimmy 日期: 2024/11/19 浏览:2)
新建项目的时候创建合理的目录结构便于后期的维护是很重要
环境:vue、webpack
目录结构:
项目子目录结构
子目录结构都差不多,主要目录是在src下面操作
src目录结构
src/common 目录
主要用来存放公共的文件
src/components
主要用来存放公共的组件
src/config
用来存放配置文件,文件目录如下
src/config/index.js 配置目录入口文件
import api from './website' // 当前平台 export const HOST_PLATFORM = 'WEB' // 当前环境 export const NODE_ENV = process.env.NODE_ENV || 'prod' // 是否开启监控 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, // 图标地址 imgUrl: `${api}/api/system/icon.do"htmlcode">/** * 动态匹配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].apisrc/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) // 自定义请求拦截逻辑,可以处理权限,请求发送监控等 // console.log(request.url) // if (localStorage.getItem('token') === null && request.url.indexOf('login') === -1) { // console.log('[*] 当前用户没有登录!!') // 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 需求变动,网站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格式公共参数 Object.keys(publicParams).forEach(key => { request.data.append(key, publicParams[key]) }) newData = request.data } else { // 合并公共参数 newData = Object.assign(request.data, publicParams) // 判断是否采用json格式提交参数 !request.isJSON && (newData = Qs.stringify(newData)) } // 不同提交参数方式给不同的字段赋值 if (request.method.toUpperCase() === 'POST') { request.data = newData } else if (request.method.toUpperCase() === 'GET') { request.params = newData } // 加载效果 request.loading && Indicator.open(request.loading) // 输出请求数据 CONSOLE_REQUEST_ENABLE && console.info(`%c 请求接口地址:${request.url} 请求接口名称:${request.desc} 请求参数JSON: ${JSON.stringify(request.data, '', 2)} `, 'color: #f60') return request } /** * 请求拦截器(失败) * @param {object} requestError 请求报错对象 * @return {object} 返回promise对象 */ export function requestFailFunc(requestError) { // 自定义发送请求失败逻辑,断网,请求发送监控等 return Promise.reject(requestError) } // 你就是个sx /** * 响应拦截器(成功) * @param {object} responseObj 响应对象 */ export function responseSuccessFunc(responseObj) { // 自定义响应成功逻辑,全局拦截接口,根据不同业务做不同处理,响应成功监控等 // 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() // 响应对象 let resData = typeof responseObj.data === 'object' "htmlcode">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) { // 打印路由数据 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;') // 登录状态验证 if (to.meta.requireLogin) { (localStorage.getItem('token')) "text-align: center">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目录
主要的页面文件,目录结构主要按照层次结构来分。
ex:该页面主要跟医生相关,主要包含云搜索(cloud)、个人中心(myCenter)、工作中心(workCenter)、搜索(serach)、同理子层级也同样区分、目录结构如下
至于公共页面可以放在common文件目录下,也可以摆在文件夹外面。
src/plugins目录
也是配置文件目录
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 "htmlcode">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 axiosInstancesrc/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 routerInstancesrc/router目录
路由配置文件目录,同理按照页面的层次结构来,结构如下
我们来看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 routessrc/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 目录
接口配置文件目录,根据页面来定义文件
同理我们只看src/service/api/index.js 和src/service/api/login.js、src/pages/login/index.vue以及页面如何调用接口即可。
src/service/api/login.js
先定义好login接口
const login = [ { methodsName: 'loginByPhone', // 方法名 method: 'POST', desc: '登录', path: '/rest/app/login', // 接口路径 mockPath: '/rest/app/login', params: { // 参数配置 这里需要注意,只有配置的这些参数才能通过接口,所以需要传递的参数都要在这里配置 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 loginsrc/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 => { }) // 这样调用登陆接口 this.$api.方法名(参数).then(res=>{}) // 方法名定义不能重名其它目录
这些目录还是包含很多东西,用户的信息保存,主体,工具函数这些,就不多说了。
对于项目的维护还是需要看重,后期维护方便也便于管理。
总结
以上所述是小编给大家带来的Vue+webpack项目配置便于维护的目录结构的相关知识,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!
荣耀猎人回归!七大亮点看懂不只是轻薄本,更是游戏本的MagicBook Pro 16.
人们对于笔记本电脑有一个固有印象:要么轻薄但性能一般,要么性能强劲但笨重臃肿。然而,今年荣耀新推出的MagicBook Pro 16刷新了人们的认知——发布会上,荣耀宣布猎人游戏本正式回归,称其继承了荣耀 HUNTER 基因,并自信地为其打出“轻薄本,更是游戏本”的口号。
众所周知,寻求轻薄本的用户普遍更看重便携性、外观造型、静谧性和打字办公等用机体验,而寻求游戏本的用户则普遍更看重硬件配置、性能释放等硬核指标。把两个看似难以相干的产品融合到一起,我们不禁对它产生了强烈的好奇:作为代表荣耀猎人游戏本的跨界新物种,它究竟做了哪些平衡以兼顾不同人群的各类需求呢?