抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Mr.wang

Time flies and people come and go

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>
<!-- built files will be auto injected -->
<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 }))//在1000000B大小下的都转为base64
},

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;
// axios初始化:延迟时间,主路由地址
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)
// 函数进入then后面的第二个err函数,如果没有就进入catch函数, 表单提交就可以根据这个重置参数以及重置按钮状态,防止按钮卡滞
// return Promise.reject(error)
}
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)
}
// 终止Promise调用链
return error
// return new Promise(() => {})
}
});

// 是否销毁拦截器
// 1.给拦截器起个名称 var myInterceptors = instance.interceptors.requesst.use();
// 2.instance.interceptors.request.eject(myInterceptor);


//模块化导出
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
//初始化css样式
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' //element-ui的全部组件
import 'element-ui/lib/theme-chalk/index.css' //element-ui的css
Vue.use(ElementUI, {
size: 'small',
zIndex: 3000
})
//全局绑定axios
Vue.prototype.$http = axios;
//初始化css样式
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.push
Router.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.push
Router.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" ? "./" : "/",
// outputDir: 在npm run build时 生成文件的目录 type:string, default:'dist'
// outputDir: 'dist',
// pages:{ type:Object,Default:undfind }
assetsDir: "./",
productionSourceMap: false,
devServer: {
port: 80, // 端口号
host: "127.0.0.1",
https: false, // https:{type:Boolean}
disableHostCheck: true,
// open: true, //配置自动启动浏览器
// proxy: 'http://dev.dsp.kuafugame.com/' // 配置跨域处理,只有一个代理
// proxy: {
// "/api": {
// target: "<url>",
// ws: true,
// changeOrigin: true
// },
// "/foo": {
// target: "<other_url>"
// }
// } // 配置多个代理
},
};

增加额外的配置

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
//压缩代码的npm包
const CompressionPlugin = require("compression-webpack-plugin")
module.exports = {
// 判断是在什么环境下运行
publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
// outputDir: 在npm run build时 生成文件的目录 type:string, default:'dist'
// outputDir: 'dist',
// pages:{ type:Object,Default:undfind }
assetsDir: "./",
productionSourceMap: false,
//修改端口号
devServer: {
port: 80, // 端口号
host: "127.0.0.1",
https: false, // https:{type:Boolean}
//内网打通
disableHostCheck: true,
// open: true, //配置自动启动浏览器
// proxy: 'http://dev.dsp.kuafugame.com/' // 配置跨域处理,只有一个代理
// proxy: {
// "/api": {
// target: "<url>",
// ws: true,
// changeOrigin: true
// },
// "/foo": {
// target: "<other_url>"
// }
// } // 配置多个代理
},
//合并一下webpack的配置
configureWebpack: config => {
//外部引入第三方库,不想打包进vender时
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, //对超过10k的数据压缩
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(
/* webpackChunkName: "home" */ '@/views/home/index.vue'
),
},

评论