vue-cli项目开发中的结构,打包配置,axios封装,vuex使用
项目结构
解析:项目存在public(公共) favicon.ico(网站图标) index.html(入口文件)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <!DOCTYPE html > <html lang ="en" > <head > <meta charset ="utf-8" > <meta http-equiv ="X-UA-Compatible" content ="IE=edge" > <meta name ="viewport" content ="width=device-width,initial-scale=1.0" > <link rel ="icon" href ="<%= BASE_URL %>favicon.ico" > <link rel ="stylesheet" href ="https://unpkg.com/element-ui/lib/theme-chalk/index.css" > <title > 网站名</title > </head > <body > <noscript > <strong > We're sorry but advertisement doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript > <div id ="app" > </div > <script src ="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.runtime.min.js" > </script > <script src ="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js" > </script > <script src ="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js" > </script > <script src ="http://jira.finway.com.cn/vue-source/axios.min.js" > </script > <script src ="https://unpkg.com/element-ui/lib/index.js" > </script > </body > </html >
此入口采用cdn引入外部的element-ui axios vue vue-router moment
src src作为项目的资源文件存放路径-包含以下的子文件夹
assets 存放images,JSON文件
调用时可以使用 路径 “@/assets/images/“+”图片名”
配置vue.config.js可改变图片打包base63限制大小
1 2 3 4 5 6 7 chainWebpack: config => { config.module .rule('images' ) .use('url-loader' ) .loader('url-loader' ) .tap(options => Object .assign(options, { limit : 1000000 })) },
components(自定义公共组件) 如果你创建了一些公共组件 在整个项目中多次调用时,可以拆分为单独的公共组件
request(请求)/api 对于axios的二次封装 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 import axios from "axios" import router from '../router' import {Message} from 'element-ui' axios.defaults.withCredentials = true ; let instance = axios.create({ baseURL: process.env.VUE_APP_BASE_API, timeout: 10000 , }); instance.interceptors.request.use( config => { config.headers = { 'Content-Type' :'application/x-www-form-urlencoded' } return config; }, error => { Promise .reject(error) }); instance.interceptors.response.use( response => { if (response.status === 200 || response.status === 304 || response.status === 201 ) { return response.data.data } return response; }, error => { if (error && error.response) { if (error.response.status === 400 || String (error).indexOf('code 400' ) !== -1 ) { Message.error(error.response.data.message) return Promise .reject(error.response.data) } if (error.response.status === 401 || String (error).indexOf('code 401' ) !== -1 ) { Message.error(error.response.data.message) } if (String (error).indexOf('code 500' ) !== -1 ) { if (error.response.data.message) { Message.error(error.response.data.message) } else { Message.error('服务器出现问题,请刷新重试' ) } return Promise .reject(error) } return error } }); export default { get (url, params = {} ) { if (!url) return ; return instance({ method: 'get' , url: url, params, timeout: 30000 }) }, post (url, data = {} ) { if (!url) return ; return instance({ method: 'post' , url: url, data, timeout: 3000000 }) }, postFile (url, data ) { if (!url) return ; return instance({ method: 'post' , url: url, data }) }, put (url, data ) { if (!url) return ; return instance({ method: 'put' , url: url, data }) }, patch (url, data ) { if (!url) return ; return instance({ method: 'patch' , url: url, data }) }, delete (url, data ) { if (!url) return ; return instance({ method: 'delete' , url: url, data, timeout: 30000 }) }, }
在自定义的分类api中把请求路径进行分类
1 2 3 4 5 6 7 8 9 10 11 12 13 import axios from "../axios" ;function login (params ) { return axios.post("/api/login" , params); } function logout ( ) { return axios.get("/api/logout" ); } export { login, logout };
store store-modules 定义 wang.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import {getRegionData,} from "@/request/api/addPlan" ;const state = { City: [], }; const getters = {};const mutations = { setCity (state, payload ) { state.City = payload; }, }; const actions = { async getCIty({ commit }, payload) { const res = await getRegionData({ access_token: payload.access_token }); commit("setCity" , res.data); }, }; export default { namespaced: true , state, getters, actions, mutations };
注意必须在store-index.js(入口)引入
1 2 3 4 5 6 7 8 9 10 11 import Vue from 'vue' import Vuex from 'vuex' import wang from './modules/wang' Vue.use(Vuex) export default new Vuex.Store({ modules: { wang, }, getters })
对于getters的使用 定义getters.js
1 2 3 4 const getters = { City: state => state.wang.City, } export default getters
在页面.vue使用
1 2 3 4 5 6 7 8 9 10 11 12 import { mapGetters } from "vuex" ;export default {computed: { ...mapGetters(["City" ]) }, methods:{ wang ( ) { console .log(this .City) } } }
styles(css样式) 分成element.css(修改UI的样式),index.css(主要的样式),reset.css(样式初始化)
index.js
1 2 3 @import './reset.css' ;@import './icon.css' ;@import './element.css' ;
在main.js引入
1 2 import '@/styles/index.css'
utils(工具) 每个项目特有的工具函数,封装了对应项目需要的公共函数
views(视图) 包含Home.vue (主体视图窗口) 布局容器的使用及插槽
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 <template> <div class ="home" > <!-- 主体框架 --> <el-container> <el-aside :style="isCollapse ? {width:0+'px'} : {width:200+'px'}" > <Aside /> </el-aside> <el-container> <el-header> <Header /> </el-header> <!-- router-view插槽 --> <el-main> <router-view></router-view> </el-main> </el-container> </el-container> </div> </template> <script> import { mapGetters } from "vuex" ;import Header from "../components/header" ;import Aside from "../components/aside" ;export default { computed: { ...mapGetters(["isCollapse" ]) }, name: "home" , data ( ) { return { width: 200 }; }, components: { Header, Aside }, }; </script> <style lang="less" scoped> .home { min-width: 1263px; height: 100 %; } </style>
在views定义的模板.vue都需要在路由进行引入
App.vue 只有一个路由插槽
1 2 3 4 5 6 7 8 9 <template> <div id="app" > <router-view/> </div> </template> <style> </style>
main.js(主要文件) main用于外部资源的引入以及vue的全局绑定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import Vue from 'vue' import App from './App.vue' import router from './router' import axios from './request/axios' import store from './store/index' import ElementUI from 'element-ui' import 'element-ui/lib/theme-chalk/index.css' Vue.use(ElementUI, { size: 'small' , zIndex: 3000 }) Vue.prototype.$http = axios; import '@/styles/index.css' Vue.config.productionTip = false new Vue({ router, store, render: h => h(App) }).$mount('#app' )
router.js(路由) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 import Vue from 'vue' import Router from 'vue-router' import Home from './views/Home.vue' Vue.use(Router) const originalPush = Router.prototype.pushRouter.prototype.push = function push (location ) { return originalPush.call(this , location).catch(err => err) } export default new Router({ routes: [{ path: '/' , name: 'home' , component: Home, redirect: '/popularize' , children: [{ path: '/popularize' , name: 'popularize' , component: resolve => require (['@/views/popularize/popularize.vue' ], resolve) } ] }, ] })
vue-router(版本3.0.6)->vue-router(版本3.2.0)才出现这个问题
在最新的vue-router中已经解决这个问题 可删除
1 2 3 4 5 const originalPush = Router.prototype.pushRouter.prototype.push = function push (location ) { return originalPush.call(this , location).catch(err => err) }
路由的懒加载方式
1 2 3 component: resolve => require (['@/views/popularize/popularize.vue' ], resolve) component: () => import ('@/views/popularize/popularize.vue' )
.env.development(开发模式的环境变量) 在开发中有一些需要单独抽离的变量
api请求的baseUrl(注意命名必须前缀带VUE_APP__)
1 VUE_APP_BASE_API ='http://dev.dsp.api.kuafugame.com'
在axios.js中使用
1 process.env.VUE_APP_BASE_API
.env.production(上线后的环境变量,为打包所使用) .gitignore(npm忽略清单)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 .DS_Store node_modules /dist # local env files .env.local .env.*.local # Log files npm-debug.log* yarn-debug.log* yarn-error.log* # Editor directories and files .idea .vscode *.suo *.ntvs* *.njsproj *.sln *.sw?
在项目准备上线后,请配置好vue.config.js
最基本的配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 module .exports = { publicPath: process.env.NODE_ENV === "production" ? "./" : "/" , assetsDir: "./" , productionSourceMap: false , devServer: { port: 80 , host: "127.0.0.1" , https: false , disableHostCheck: true , }, };
增加额外的配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 const CompressionPlugin = require ("compression-webpack-plugin" )module .exports = { publicPath: process.env.NODE_ENV === "production" ? "./" : "/" , assetsDir: "./" , productionSourceMap: false , devServer: { port: 80 , host: "127.0.0.1" , https: false , disableHostCheck: true , }, configureWebpack: config => { config.externals = { 'vue' : 'Vue' , 'vue-router' : 'VueRouter' , 'moment' : 'moment' , 'axios' : 'axios' , 'element-ui' : 'ELEMENT' , } config.plugins.push(new CompressionPlugin({ test: /\.js$|\.html$|.\css/ , threshold: 10240 , deleteOriginalAssets: false })) }, chainWebpack: config => { config.plugins.delete("prefetch" ) }, };
vue的import导入是指向index(包含vue js文件)
可以多个组件写入components,使用index.js导出
1 2 3 4 5 6 7 8 -view -components -one -index.vue -two -index.vue -index.js -index.vue
index.js
1 2 export { default as One } from './one' export { default as Two } from './two'
使用组件
1 import { One, Two } from "./components" ;
vuex的模块动态注入
index.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import Vue from 'vue' import Vuex from 'vuex' import getters from './getters' const modulesFiles = require .context('./modules' , true , /\.js$/ )const modules = modulesFiles.keys().reduce((modules, modulePath ) => { const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/ , '$1' ) const value = modulesFiles(modulePath) modules[moduleName] = value.default return modules }, {}) export default new Vuex.Store({ modules, getters })
css的变量导出使用
less
1 2 3 4 5 6 @blue:#324157; @light-blue:#3A71A8; :export { blue: @blue; lightBlue: @light-blue; }
index.vue使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <template> <div :style="{background:variables.blue}"> {{variables.lightBlue}} </div> </template> <script> import variables from "@/styles/variables.less"; export default { computed: { variables() { return variables; }, }, }; </script>
一个为了刷新页面的重定向vue
可以再需要刷页面的地方使用,保留了路由以及query参数
1 2 3 4 5 6 7 8 9 10 11 12 <script> export default { created() { const { params, query } = this.$route const { path } = params this.$router.replace({ path: '/' + path, query }) }, render: function(h) { return h() // avoid warning message } } </script>
进度条的使用
在主vue文件中-app.vue
主要是监听路由的变化来生成进度条
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <template> <div id="app" > <router-view /> <vue-progress-bar /> </div> </template> <script> import VueProgressBar from 'vue-progressbar' export default { components:{VueProgressBar}, name: "App" , created ( ) { this .$Progress.start(); this .$router.beforeEach((to, from , next ) => { this .$Progress.start(); next(); }); this .$router.afterEach((to, from ) => { this .$Progress.finish(); }); }, mounted ( ) { this .$Progress.finish(); }, }; </script>
路由打包名称
webpackChunkName 可以指定在打包后的模块名称
1 2 3 4 5 6 7 { path: 'home' , name: 'Home' , component: () => import ( '@/views/home/index.vue' ), },