教你如何封装灵活高复用的vue框架?
前言:一般我们在创建vue项目的时候比较多的采用官方的vue-cli2脚手架去构建项目,一般来说这种模式创建的项目也不需要过多的配置即可使用,但是有一个痛点就是每个项目都需要重新构建和配置,那有没有一种方式可以省去这些繁琐的过程呢,比如说我们有两个同样的项目,使用的都是vue框架,或者说我们之前配置好的一些项目我们想拿过来直接用。今天我们就聊一聊如何去基于vue构建一套可复用,灵活配置的框架,保证我们在需要使用是直接拿过来就可以用 。
总体来说我们需要考虑三点:
1、接口api的管理
2、路由的管理
3、公用数据的管理
4、公用方法的管理
一、接口api的管理
首先我们说说接口api如何统一的管理起来,在调用的时候能方便快捷,并且能减少http的请求,优化使用体验和节省资源。 目前vue-cli3已经更新使用很长时间了,建议大家使用vue-cli3脚手架去构建项目
我们在封装好axios请求的时候就应该考虑api如何去统一的管理起来,这对项目的优化层面来说非常重要,因为管理api可以很大的减少http的请求来节省服务资源提升响应速度。
例如我们这样做,新建一个api文件,在api文件下新建index.js专门存放后期需要使用到的接口:
import request from '@/request/axios'//这个就是我们封装好的axios文件
var ENV =process.env.NODE_ENV
var Tenv;
ENV=='development'?Tenv='/api':Tenv=''
// 接口封装请求示例
export const getDiaryList = (pageIndex,pageSize) => {
return request({
url: Tenv+'/getDiaryList/list',
method: 'get',
params: {
pageIndex:pageIndex,
pageSize:pageSize,
}
})
}
顺便贴上我的axios的封装代码:
import axios from 'axios'
import NProgress from 'nprogress'//这是导航栏的请求状态动画插件,具体见下图
import 'nprogress/nprogress.css'
axios.defaults.timeout = 10000;
//返回其他状态吗
axios.defaults.validateStatus = function (status) {
return status >= 200 && status <= 500; // 默认的
};
//跨域请求,允许保存cookie
axios.defaults.withCredentials = true;
NProgress.configure({
showSpinner: false
});
//HTTPrequest拦截
axios.interceptors.request.use(config => {
NProgress.start();
const meta = (config.meta || {});
const isToken = meta.isToken === false;
//headers中配置serialize为true开启序列化
return config
}, error => {
return Promise.reject(error)
});
//HTTPresponse拦截
axios.interceptors.response.use(res => {
NProgress.done();
const status = res.data.code || 200;
const message = res.data.msg || '未知错误';
if (status !== 200) {
return Promise.reject(new Error(message))
}
return res;
}, error => {
NProgress.done();
return Promise.reject(new Error(error));
});
export default axios;
NProgress就是做这个事的,当然不要也可以,因为我这是一个后台管理系统:
这样一来,我们有多个api的话可以直接管理起来,或者有多个类型的也可以分文件存放,用的话只需要引入就可以了,因为们发现好多初学者都直接在页面内每次都调用axios.get这样的方式
页面引入api文件:
import {getDiaryList} from '@/api/index'
//可以是一个对象下面有多个
使用:
getDiaryList(pageIndex,pageSize){
getDiaryList(pageIndex,pageSize).then(res=>{
// 请求成功处理
console.log(res.data)
}).catch(res=>{
//请求失败处理
console.log('请求失败')
})
},
二、路由的管理
为什么要做路由的管理呢,路由可以说是vue的灵魂所在,之前我就接手过一个项目,所有的路由全部在router下index的文件里写着,也没有父子之分,使用查找起来极为不方便。
关于路由的管理,我们可以在router下新建一个文件夹专门去管理路由,比如说这个文件夹名叫RouterPage,我们可以分模块分页面去管理,比如说我们可以在RouterPage下新建一个index.js管理公用、分模块的页面路由,这样在使用上也可以方便很多,管理上也轻松了许多,不至于我们下次交给别人的时候一脸茫然。
比如我们的RouterPage下index.js文件可以是这样的:
export default [
{ path: "/", redirect: '/index',},
{
path: '/index',
name: '首页',
component: () => import( '@/views/index'),
meta: { requireAuth: true},//是否检查登录,
children:[
{
path:'/',
name:'登录页',
component: () => import( '@/views/home'),
},
]
},
{
path: '/login',
name: '登录页',
component: () => import( '@/views/login'),
meta: { requireAuth: false}
},
]
我们在router下的index.js文件直接import再添加路由加可以使用了,在上面RouterPage下的index.js我们可以去配置公用的、模块的等各种路由;
import Vue from 'vue'
import VueRouter from 'vue-router'
import RouterPage from './RouterPage/'//引入我能创建的RouterPage文件名,
Vue.use(VueRouter)
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
})
router.addRoutes([...RouterPage]);//添加路由
export default router
还有一点我觉的在封装的是肯定会考虑到,项目也肯定会用到,就是检查当前打开的页面用户是否登录、是否需要登录,可以根据路由的全局监测去控制,可以在src目录下新建一个inspect.js文件专门去管理控制:
import router from './router'
import Cookies from 'js-cookie'//操作cookie的插件
router.beforeEach((to, from, next) => {
//Cookies.set('isAuth', 'iii', { expires: 1 });
//to.matched.some(record => record.meta.requireAuth)这个就是我们再路由中设置的meta下requireAuth的属性,为true即表示需要判断是否登录,为false就不用判断
if (to.matched.some(record => record.meta.requireAuth)) {
if (Cookies.get('isAuth')) { //判断的条件可以自定,我这里是cookie判断,登录了会存储isAuth
if (to.fullPath == '/login') {
} else {
next()
}
} else {
next({
path: '/login',
query: { redirect: to.fullPath }
})
}
} else {
Cookies.remove('isAuth');
next()
}
})
然后把这个文件在main.js全局引入就可以了,就可以实现路由变化是监测用户是否登录或者登录是否过期。
三、公用数据的管理
关于公用数据的管理,官方已经提供了一种完美的方法,就是vuex状态数据管理,这个我有一篇文章专门说过如果去使用vuex,不会的可以去看看。
vuex使用教程
当然还有另外一种方法,就是json数据管理方法,这种的话也可以实现本地公用数据的管理,但我还是建议使用官方的vuex。
比如说我们有一个导航,需要去做本地菜单的预配置,我为什么不采用vuex的原因是,有可能我们菜单会有二级三级甚至四级放在vuex里或比较影响数据的直观性,那么我们可以这样做,创建一个nav.config.js:
let results={
title:'管理平台',
icon:'el-icon-s-platform',
tab:[
{name:'导航1',path:'/index/login','icon':'el-icon-s-check',children:[
{name:'子集',path:'/','icon':'el-icon-s-check'},
{name:'子集1',path:'/','icon':'el-icon-s-check'},
{name:'子集2',path:'/','icon':'el-icon-s-check'},
{name:'子集3',path:'/','icon':'el-icon-s-check'},
{name:'子集4',path:'/','icon':'el-icon-s-check'},
]},
{name:'导航7',path:'/index/home','icon':'el-icon-s-check'},
{name:'用户管理',path:'/index/login','icon':'el-icon-menu',children:[
{name:'子集1',path:'/','icon':'el-icon-s-check'},
{name:'子集1',path:'/','icon':'el-icon-s-check'},
{name:'子集2',path:'/','icon':'el-icon-s-check',children:[
{name:'子集11',path:'/','icon':'el-icon-s-check'},
{name:'子集12',path:'/','icon':'el-icon-s-check'},
{name:'子集23',path:'/','icon':'el-icon-s-check'},
{name:'子集34',path:'/','icon':'el-icon-s-check'},
{name:'子集45',path:'/','icon':'el-icon-s-check'},
]},
{name:'子集3',path:'/','icon':'el-icon-s-check'},
{name:'子集4',path:'/','icon':'el-icon-s-check'},
]},
{name:'导航9',path:'/index/login','icon':'el-icon-s-check'},
{name:'导航10',path:'/index/login','icon':'el-icon-s-check'}
]
}
export default {
results
}
然后在需要的文件引入或者赋值给vuex的state上:
import navConfig from'../nav.config'
data(){
return {
tabResults:navConfig.results,
}
},
这样我们就可以直接在特定的文件去使用this.tabResults去操作或者页面直接绑定使用了,也是非常的方便,多用于本地菜单的配置,可以灵活管理,如:
四、公用方法的管理
公用方法的管理其实可公用数据的管理差不多的,vuex也可以实现,但是我们一般的还是习惯于管理在公用的方法文件中,达到直观、方便、灵活的效果。
比如我们可以新建一个utils.js:
export function dateFormat(date, format) {
format = format || 'yyyy-MM-dd hh:mm:ss';
if (date !== 'Invalid Date') {
let o = {
"M+": date.getMonth() + 1, //month
"d+": date.getDate(), //day
"h+": date.getHours(), //hour
"m+": date.getMinutes(), //minute
"s+": date.getSeconds(), //second
"q+": Math.floor((date.getMonth() + 3) / 3), //quarter
"S": date.getMilliseconds() //millisecond
}
if (/(y+)/.test(format)) format = format.replace(RegExp.$1,
(date.getFullYear() + "").substr(4 - RegExp.$1.length));
for (let k in o)
if (new RegExp("(" + k + ")").test(format))
format = format.replace(RegExp.$1,
RegExp.$1.length === 1 ? o[k] :
("00" + o[k]).substr(("" + o[k]).length));
return format;
}
return '';
}
export function toFormData(obj) {
const data = new FormData();
Object.keys(obj).forEach(key => {
data.append(key, Array.isArray(obj[key]) ? obj[key].join(',') : obj[key]);
});
return data;
}
可以在main.js分别引入或者全部引入
分别引入,只使用一个或多个方法:
import { toFormData } from './utils'
全部引入:
import Utils from './utils'
//使用
Utils.toFormData(obj)
总结:以上呢我们从四个方面说了下如何封装属于自己的可复用的vue框架,比较建议的做法的就是封装好一个保存起来,可以放在阿里code上也可以放在github上,这样我们下次再使用的时候直接dowm下来做基本的代理或者域名配置就可以,能极大的节省很多时间,避免重复的工作。
好了欢迎大家关注我的博客小程序(目前在正在完善),我们一起学历交流,一起进步成长。