登录+动态路由+按钮权限控制

99 阅读2分钟
next('xxx') 再一次走router.beforeEach路由守卫回调, next()表示加载路由
  1. 登录路由判断 判断token存在, 使用store插件,可以限制token存在的时间(在生成一个带有时间的token如_expireTimeToken = 1234123132) token 不存在,重定向/login,通过allowList判断,加载login路由
const allowList = ['login']
router.beforeEach((to: any, from, next) => {
	const token = storage.get('ACCESS_TOKEN')
	if (token) {
                ...
		next()
	} else if (allowList.includes(to.name)) {
		next()
	}  else {
		next('/login')
	}
	
})
  1. 动态路由

vuex state routes属性,判断路由存在, 页面一刷新就不在了。防止正常页面点击加载路由,进行动态路由添加。

const allowList = ['login']
router.beforeEach((to: any, from, next) => {
	const token = storage.get('ACCESS_TOKEN')
	if (token) {
		if (store.state.routes.length == 0) {
			store.dispatch('GenerateRoutes')
			// 动态添加路由后,再次重定向默认路径或网址路径
			// next('xxx') 再一次走router.beforeEach路由守卫回调, next()表示加载路由
			next(to.path == '/' ? '/aggregator' : to.path)
		} else {
			// 判断加载路由成功后,breadInfoArr面包屑变化,navMenuInfoArr 左侧导航栏变化
			const r_path_arr = to.path.split('/')
			r_path_arr.shift()
			breadInfoArr.value = r_path_arr
			navMenuInfoArr.value = to.meta.level ? r_path_arr.slice(0, -(to.meta.level - 1)) : r_path_arr
			
			// 带参数的url页面,点击左上角刷新参数缺失问题
			if (to.redirectedFrom && to.redirectedFrom.path == to.path && to.redirectedFrom.query != to.query) {
				to.query = to.redirectedFrom.query
				to.fullPath = to.redirectedFrom.fullPath
			} 
			next()
		}
	} else if (allowList.includes(to.name)) {
		next()
	} else if (from.name == 'login') {
                // 登陆页面,没有token,阻止重定向其他页面
		next(false)
	} else {
		next('/login')
	}
	
})

vuex

createStore({
  state: {
	  routes: []
  },
  
  mutations: {
	 
	  SET_ROUTERS: (state, routes) => {
	    state.routes = routes
	  }
  },
  actions: {
	  Logout ({ commit }) {
		  commit('SET_ROUTERS', [])
	  },
	  GenerateRoutes ({ commit }, data) {
	    return new Promise(resolve => {
            // 过滤路由
			const accessedRouters = filterRouter(['home', 'dashboard', 'form'])
			commit('SET_ROUTERS', accessedRouters)
			resolve(accessedRouters)
	    })
	  }
  },
  modules: {
  }
})

const filterRouter = (permission: string[]) => {
	permission_arr = permission
	// 过滤动态路由列表
	const routers = filterAsyncRouter(router_config)
	
	// 往路由router中添加 过滤后的路由
	addNavRouters(routers)
	// 导航菜单数据 赋值
	filterRoutes.value = routers
	
	return routers
}

addNavRouters = (rs: Array<RouteRecordRaw>, parentName = 'index') => {
	// 登出后,会删除index组件,需要添加回来
	if (!router.hasRoute('index')) {
		router.addRoute(common_router[0])
	}
	rs.forEach((r) => {
		router.addRoute(parentName, r)
	})
	return router
}

// 登出
const logout = () => {
		store.dispatch('Logout')
		router.push('/login')
		router.removeRoute('index')
	}
  1. 按钮权限控制

    使用自定义指令实现,官方文档链接 app.directive 注册全局指令。mounted 和 updated 生命周期,相同的行为,采用简化方式书写。响应式变量使用arg. el 和 binding解释看官方文档 authDirective函数书写权限控制逻辑

const authDirective = (el, binding) => {
  // mounted 和 updated 生命周期,相同的行为
  // arg v-auth:[responed] responed响应式的变量
  el.style.display = binding.arg != "delete" ? "none" : "block"
}
app.directive("auth", authDirective)

指令使用, newshow 是响应式变量

<a-button v-auth:[newshow] class="add-btn" type="primary" @click="edit(0)">
   <template #icon>
   <plus-outlined />
   </template>
   新增
</a-button>
const newshow = ref('delete')