项目初始化
利用vue-cli3进行可视化项目的初始化,参考 blog.csdn.net/qq_40636998…
目录介绍
权限路由
权限路由主要作用是进行权限的认证,不同角色进入到系统给出不同的菜单以及路由,大部分权限路由是通过在router中设置路由拦截器 beforeEach 进行判断Cookie或者Session是否已经存在登录验证的Token,如果有就进行下一步的操作去后端获取路由信息,没有就弹出到登录页。
需要注意用户的信息和路由都是存储在vuex中,这样刷新页面,都会重新去获取,这样做是解决了在另一端修改了此用户的信息或者权限,本机能及时的更新信息。菜单以及路由都是存储在vuex中进行刷新的。
router.beforeEach((to, from, next) => {
const token = store.state.user.token || '';
if (token) { // 判断是否有token
if (to.path === '/userlogin/login') {//判断是否跳转到登录页,如果有token把跳转登录页的请求直接重置到主页
next({
path: '/'
});
} else {
if (store.getters.username.length === 0) { // 判断当前用户是否已拉取完user_info信息(在vuex中存储了用户信息)
store.dispatch('user/GetInfo').then(() => { // 拉取用户信息
store.dispatch('permission/GenerateRoutes').then(() => { // 生成可访问的路由表
router.addRoutes(store.getters.addRouters) // 动态添加可访问路由表(从vuex中获取)
next({
...to,
replace: true
}) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave a history record
})
}).catch(err => {
console.log(err);
});
} else {
next() //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的全面会自动进入404页面
}
}
} else {
if (to.path.includes('/userlogin')) {
next();
} else {
next('/userlogin'); // 否则全部重定向到登录页
}
}
});
keep-alive多级缓存
后台项目中多级缓存是非常常见的,多是用于顶部的导航栏上,路由层级为三级的时候需要做特殊的处理
在需要缓存的router-view上进行keep-alive包裹,cachedView就是需要缓存的路由名称
<template>
<keep-alive :include="cachedViews">
<router-view :key="key"></router-view>
</keep-alive>
</template>
<script>
computed: {
cachedViews() {
return this.$store.state.tagsView.cachedViews;
},
}
</script>
在vuex中队需要缓存的页面进行存储,在多级的路由需要将路由的父级路由加入的缓存的cachedViews中,不然无法缓存成功,而且每一个vue页面都需要加上name:""这个属性,以此来识别需要缓存的页面。在清除缓存中需要将缓存中父级页面的名称也清除掉,不然页面还是会有缓存。
const state = {
visitedViews: [],
cachedViews: [],
cachedViewsParent: []//存储每个路由的父级信息
}
const mutations = {
ADD_VISITED_VIEW: (state, view) => {
if (state.visitedViews.some(v => v.path === view.path)) return
state.visitedViews.push(
Object.assign({}, view, {
title: view.meta.title || 'no-name'
})
)
},
ADD_CACHED_VIEW: (state, view) => {
//多级缓存
if (state.cachedViews.includes(view.name)) return
view.matched.map(item => {
//不缓存首页
if (item.name.indexOf('home') == -1 && state.cachedViews.indexOf(item.name) == -1) {
state.cachedViews.push(item.name)
}
});
//不缓存首页
if (!view.name.includes('home')) {
state.cachedViewsParent.push({
name: view.name,
parent: view.matched.filter(item => item.name.indexOf('home') == -1).map(item => item.name)
});
}
},
DEL_VISITED_VIEW: (state, view) => {
for (const [i, v] of state.visitedViews.entries()) {
if (v.path === view.path) {
state.visitedViews.splice(i, 1)
break
}
}
},
DEL_CACHED_VIEW: (state, view) => {
let arr = [];
state.cachedViewsParent = state.cachedViewsParent.filter(item => item.name != view.name);
//同级情况下不删除上级路由
state.cachedViewsParent.map(i => [
arr.push(...i.parent)
]);
view.matched.map(item => {
if (!arr.includes(item.name)) {
const index = state.cachedViews.indexOf(item.name)
index > -1 && state.cachedViews.splice(index, 1)
}
})
},
DEL_OTHERS_VISITED_VIEWS: (state, view) => {
state.visitedViews = state.visitedViews.filter(v => {
return v.meta.affix || v.path === view.path
})
},
DEL_OTHERS_CACHED_VIEWS: (state, view) => {
const index = state.cachedViews.indexOf(view.name)
if (index > -1) {
state.cachedViews = state.cachedViews.slice(index, index + 1)
} else {
// if index = -1, there is no cached tags
state.cachedViews = []
}
},
DEL_ALL_VISITED_VIEWS: state => {
// keep affix tags
const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
state.visitedViews = affixTags
},
DEL_ALL_CACHED_VIEWS: state => {
state.cachedViews = []
},
UPDATE_VISITED_VIEW: (state, view) => {
for (let v of state.visitedViews) {
if (v.path === view.path) {
v = Object.assign(v, view)
break
}
}
}
}
const actions = {
addView({
dispatch
}, view) {
dispatch('addVisitedView', view)
dispatch('addCachedView', view)
},
addVisitedView({
commit
}, view) {
commit('ADD_VISITED_VIEW', view)
},
addCachedView({
commit
}, view) {
commit('ADD_CACHED_VIEW', view)
},
delView({
dispatch,
state
}, view) {
return new Promise(resolve => {
dispatch('delVisitedView', view)
dispatch('delCachedView', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delVisitedView({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_VISITED_VIEW', view)
resolve([...state.visitedViews])
})
},
delCachedView({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_CACHED_VIEW', view)
resolve([...state.cachedViews])
})
},
delOthersViews({
dispatch,
state
}, view) {
return new Promise(resolve => {
dispatch('delOthersVisitedViews', view)
dispatch('delOthersCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delOthersVisitedViews({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_VISITED_VIEWS', view)
resolve([...state.visitedViews])
})
},
delOthersCachedViews({
commit,
state
}, view) {
return new Promise(resolve => {
commit('DEL_OTHERS_CACHED_VIEWS', view)
resolve([...state.cachedViews])
})
},
delAllViews({
dispatch,
state
}, view) {
return new Promise(resolve => {
dispatch('delAllVisitedViews', view)
dispatch('delAllCachedViews', view)
resolve({
visitedViews: [...state.visitedViews],
cachedViews: [...state.cachedViews]
})
})
},
delAllVisitedViews({
commit,
state
}) {
return new Promise(resolve => {
commit('DEL_ALL_VISITED_VIEWS')
resolve([...state.visitedViews])
})
},
delAllCachedViews({
commit,
state
}) {
return new Promise(resolve => {
commit('DEL_ALL_CACHED_VIEWS')
resolve([...state.cachedViews])
})
},
updateVisitedView({
commit
}, view) {
commit('UPDATE_VISITED_VIEW', view)
}
}
export default {
namespaced: true,
state,
mutations,
actions
}
当然多级路由的缓存会出现坑,同时打开多个父级路由相同的页面时,关闭清除页面无法成功的去掉路由缓存,把多级路由过滤替换成两级路由,具体可以参照 这个解决方案 segmentfault.com/a/119000003…
let allChildren = [];
// 将多级路由转换成为二级路由方便使用keep-alive(找出所有的叶子节点,平展开)
export const flatAsyncRouter = (routers) => {
searchchildren(routers)
return allChildren;
}
let searchchildren = (arr) => {
arr.map(item => {
if (item.children && item.children.length > 0) {
searchchildren(item.children)
} else {
allChildren.push(item)
}
})
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!