const externals = { vue: 'Vue', 'vue-router': 'VueRouter', vuex: 'Vuex', 'mint-ui': 'MINT', axios: 'axios' } const cdn = { // 开发环境 dev: { css: [ 'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css' ], js: [] }, // 生产环境 build: { css: [ 'https://lib.baomitu.com/mint-ui/2.2.13/style.min.css' ], js: [ 'https://lib.baomitu.com/vue/2.6.6/vue.min.js', 'https://lib.baomitu.com/vue-router/3.0.1/vue-router.min.js', 'https://lib.baomitu.com/vuex/3.0.1/vuex.min.js', 'https://lib.baomitu.com/axios/0.18.0/axios.min.js', 'https://lib.baomitu.com/mint-ui/2.2.13/index.js' ] } } configureWebpack: config => { if (isProduction) { // externals里的模块不打包 Object.assign(config, { externals: externals }) } else { // 为开发环境修改配置... } }, chainWebpack: config => { // 对vue-cli内部的 webpack 配置进行更细粒度的修改。 // 添加CDN参数到htmlWebpackPlugin配置中, 详见public/index.html 修改 config.plugin('html').tap(args => { if (process.env.NODE_ENV === 'production') { args[0].cdn = cdn.build } if (process.env.NODE_ENV === 'development') { args[0].cdn = cdn.dev } return args }) }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <!-- DNS预解析 --> <link href="https://lib.baomitu.com" /> <meta content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=0,minimal-ui,viewport-fit=cover" /> <link href="<%= BASE_URL %>favicon.ico" /> <!-- 使用CDN加速的CSS文件,配置在vue.config.js下 --> <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" as="style" /> <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" /> <% } %> <title>vuedemo</title> </head> <body> <noscript> <strong>We're sorry but vuedemo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> </noscript> <div></div> <!-- 使用CDN加速的JS文件,配置在vue.config.js下 --> <% for (var i in htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %> <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script> <% } %> <!-- built files will be auto injected --> </body> </html>
路由设计、登录拦截
const router = new Router({ routes: [ { path: 'https://www.jb51.net/', name: 'home', component: Home, meta: { auth: false, // 是否需要登录 keepAlive: true // 是否缓存组件 } }, { path: '/about', name: 'about', component: () => import(/* webpackChunkName: "about" */ './views/About.vue'), meta: { auth: true, keepAlive: true } }, { path: '/login', name: 'login', component: () => import(/* webpackChunkName: "login" */ './views/login.vue'), meta: { auth: false, keepAlive: true } }, { path: '*', // 未匹配到路由时重定向 redirect: 'https://www.jb51.net/', meta: { // auth: true, // keepAlive: true } } ] }) // 全局路由钩子函数 对全局有效 router.beforeEach((to, from, next) => { let auth = to.meta.auth let token = store.getters['login/token']; if (auth) { // 需要登录 if (token) { next() } else { next({ name: 'login', query: { redirect: to.path } }) } } else { next() } })
在meta中设置是否需要登录以及是否缓存当前组件,
在router.beforeEac路由钩子函数中对登录权限判断,没有登录的跳到登录页面,并且把当前页面传过去,登录后跳回这个页面。
对于页面缓存的在app.vue里进行处理
<keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view>
axios、api 设计
对于axios的设计主要是请求拦截器, respone拦截器,以及get,post的二次封装
axios.defaults.timeout = 12000 // 请求超时时间 axios.defaults.baseURL = process.env.VUE_APP_BASE_API axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8' // post请求头的设置 // axios 请求拦截器 axios.interceptors.request.use( config => { // 可在此设置要发送的token let token = store.getters['login/token']; token && (config.headers.token = token) Indicator.open('数据加载中') return config }, error => { return Promise.error(error) } ) // axios respone拦截器 axios.interceptors.response.use( response => { // 如果返回的状态码为200,说明接口请求成功,可以正常拿到数据 // 否则的话抛出错误 结合自身业务和后台返回的接口状态约定写respone拦截器 Indicator.close() console.log('response', response); if (response.status === 200 && response.data.code === 0) { return Promise.resolve(response) } else { Toast({ message: response.data.msg, position: 'middle', duration: 2000 }); return Promise.reject(response) } }, error => { Indicator.close() const responseCode = error.response.status switch (responseCode) { // 401:未登录 case 401: break // 404请求不存在 case 404: Toast({ message: '网络请求不存在', position: 'middle', duration: 2000 }); break default: Toast({ message: error.response.data.message, position: 'middle', duration: 2000 }); } return Promise.reject(error) } ) /** * 封装get方法,对应get请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ function get (url, params = {}) { return new Promise((resolve, reject) => { axios .get(url, { params: params }) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) } /** * post方法,对应post请求 * @param {String} url [请求的url地址] * @param {Object} params [请求时携带的参数] */ function post (url, params) { return new Promise((resolve, reject) => { axios .post(url, qs.stringify(params)) .then(res => { resolve(res.data) }) .catch(err => { reject(err.data) }) }) }
为了方便管理api路径,这里把所以请求都放在了api文件夹下,如