wordpress简洁音乐播放器,成都网络优化公司排行榜,国际传来10个最新消息,为什么中国禁止谷歌浏览器核心思想就是通过登录请求此用户对应的权限菜单#xff0c;然后跳转首页#xff0c;触发全局前置导航守卫#xff0c;在全局导航守卫中通过 addRoute 添加动态路由进去。addRoute有一个需要注意的地方#xff0c;就是我们添加完动态路由后#xff0c;地址栏上立即访问添加…核心思想就是通过登录请求此用户对应的权限菜单然后跳转首页触发全局前置导航守卫在全局导航守卫中通过 addRoute 添加动态路由进去。addRoute有一个需要注意的地方就是我们添加完动态路由后地址栏上立即访问添加的动态路由它不会跳转需要我们手动触发下push或者replace都可以进行触发。但是用在全局前置导航守卫中写法又不太一样可以参照官网说明
动态路由 | Vue Router (vuejs.org)
这是我自己练习的项目文件分布 我这里把主要文件的代码都贴出来
首先是 pinia 文件这里面主要存储了 token 与 动态路由 数据。我做了一个持久化存储
stores 里面的 counter.ts
import { ref } from vue
import { defineStore } from piniaexport const useUserStore defineStore(user, () {// tokenconst token ref()// 动态路由const dynamicRoutes ref([])// 设置tokenconst setToken (t: string) { token.value t }// 设置动态路由const setDynamicRoutes (r: any) { dynamicRoutes.value r }// 清空tokenconst clearToken () { token.value }// 清空动态路由const clearDynamicRoutes () { dynamicRoutes.value [] }return {token,dynamicRoutes,setToken,setDynamicRoutes,clearToken,clearDynamicRoutes}
}, {persist: {enabled: true // true 表示开启持久化保存}
})路由信息 router 文件夹里面的 index.ts
import { createRouter, createWebHistory } from vue-router
import HomeView from ../views/HomeView.vueconst router createRouter({history: createWebHistory(import.meta.env.BASE_URL),routes: [{path: /,name: home,component: HomeView,// 重定向的首页redirect: /test},{path: /login,name: login,component: () import(../views/Login.vue)}]
})export default router登录页面views 文件夹里面的 Login.vue
templatedivel-button clicksubmit登录/el-button/div
/templatescript setup langts
import { useUserStore } from /stores/counter
import { useRouter } from vue-routerconst userStore useUserStore()
const router useRouter()const submit () {// 模拟登录setTimeout(() {// 存储token和动态路由userStore.setToken(Bearen Xxx)userStore.setDynamicRoutes([{path: /about,name: about,children: [{ path: /about/music, name: music, component: Music },{ path: /about/movie, name: movie, component: Movie },{path: /about/parent,name: parent,children: [{ path: /about/parent/child, name: parent, component: Parents }]},]},{ path: /test, name: test, component: Test },])// 跳转路由。触发全局前置导航守卫router.replace(/)})
}
/script
点击登录页面的登录按钮后会跳转到 / ,路由变化了就会触发全局前置导航守卫全局前置导航守卫我写在了 mian.ts 文件中
自定义指令可以忽略那是我做按钮级权限用的(可以看我上一篇文章)。
需要注意的地方就是 hasAddAliveRoutes 这个变量记录是否已经添加过动态路由了如果添加过了就赋值为true。在去其他路由的时候就不会重新添加动态路由了。还有一个作用就是刷新的时候hasAddAliveRoutes会重新变为false会重新添加一下动态路由防止刷新路由丢失
import { createApp } from vue
import { createPinia } from piniaimport App from ./App.vue
import router from ./router
import ElementPlus from element-plus
import element-plus/dist/index.cssimport piniaPersist from pinia-plugin-persist
import { useUserStore } from ./stores/counterconst app createApp(App)const pinia createPinia()
app.use(pinia)
app.use(router)
app.use(ElementPlus)pinia.use(piniaPersist)// 处理动态路由,下面的全局前置导航守卫会用到
const getNewRoutes (routes: any) {let res routes.map((i: any) {return {...i,// 动态添加component,有就添加没有就不添加 (带有子级的路由是没有component的)...(i.component { component: () import(./views/${i.component}.vue) }),// 再把内层的处理一下...(i.children { children: getNewRoutes(i.children) }),}})return res
}// 是否添加过动态路由 这里的标识作用刷新的时候会变为false然后就会重新添加动态路由防止路由丢市的
let hasAddAliveRoutes false
router.beforeEach((to, from, next) {if (to.path /login) {next()} else {let token useUserStore().tokenif (token) { // 存在token// 判断是否有动态路由添加了if (!hasAddAliveRoutes) { // 没有添加,则添加动态路由并进行触发// 对pinia中的动态路由进行处理component字段只是一个文件名称不是我们想要的动态引入所以需要修改let arr getNewRoutes(useUserStore().dynamicRoutes)console.log(处理之后的路由, arr)// 开始添加动态路由for (let i 0; i arr.length; i) {router.addRoute(home, arr[i])}// 修改添加动态路由的状态hasAddAliveRoutes true// 触发添加的动态路由next(to.fullPath)} else { // 已经添加了,则直接通过next()}} else { // 不存在tokennext(/login)}}
})// 假装此用户在tset页面只有 改 和 查 的按钮权限
let buttonAuth [{ path: /test, btn: [check, change] }
]
// 自定义指令: 控制按钮级权限
app.directive(permission, {mounted(el, binding) {// console.log(el) // 元素// console.log(binding.value) // 值// console.log(binding.arg) // 路由// 遍历按钮数组根绝当前的路由找到这一项的按钮权限let btnAuth buttonAuth.find(item item.path binding.arg)if (btnAuth) { // 找到了// 不包含此按钮权限就移除按钮!btnAuth.btn.includes(binding.value) el.parentNode.removeChild(el)}}
})app.mount(#app)然后就会跳往首页了也就是 HomeView.vue 页面这个文件里面用到了递归组件MenuTree.vue
这个递归组件就是用来递归菜单的多少级菜单都能进行展示
templateel-container classlayout-container-demo styleheight: 100%el-aside :widthasideel-scrollbarel-menu:routertrue:collapseisCollapse:modemode:collapse-transitionfalse:default-active$router.currentRoute.value.pathMenuTree :routesroutes :isCollapseisCollapse/MenuTree/el-menu/el-scrollbar/el-asideel-containerel-header styletext-align: right; font-size: 12pxdiv classtoolbarel-button clickcollapse折叠菜单/el-buttonel-button clickchangeMode改变布局/el-buttonel-dropdownel-icon stylemargin-right: 8px; margin-top: 1pxsetting //el-icontemplate #dropdownel-dropdown-menuel-dropdown-itemView/el-dropdown-itemel-dropdown-itemAdd/el-dropdown-itemel-dropdown-itemDelete/el-dropdown-item/el-dropdown-menu/template/el-dropdownspan clickreback退出/span/div/el-headerel-mainel-scrollbarrouter-view/router-view/el-scrollbar/el-main/el-container/el-container
/templatescript langts setup
import { Setting } from element-plus/icons-vue
import MenuTree from ./MenuTree.vue
import { useUserStore } from /stores/counter
import { ref } from vue
import { useRouter } from vue-routerconst userStore useUserStore()
const router useRouter()// 路由
const routes ref(userStore.dynamicRoutes)
// 是否折叠
const isCollapse ref(false)
// 宽度
const aside ref(200px)
// 菜单展示方式
const mode ref(vertical)// 点击折叠菜单
const collapse () {isCollapse.value !isCollapse.valueaside.value isCollapse.value ? 60px : 200px
}
// 点击改变布局
const changeMode () {mode.value mode.value vertical ? horizontal : vertical
}
// 点击退出
const reback () {userStore.clearToken()userStore.clearDynamicRoutes()router.replace(/login)
}
/scriptstyle scoped
.layout-container-demo .el-header {position: relative;background-color: var(--el-color-primary-light-7);color: var(--el-text-color-primary);
}.layout-container-demo .el-aside {color: var(--el-text-color-primary);background: var(--el-color-primary-light-8);/* 新加的过度效果 */transition: width 0.15s;-webkit-transition: width 0.15s;-moz-transition: width 0.15s;-webkit-transition: width 0.15s;-o-transition: width 0.15s;
}.layout-container-demo .el-menu {border-right: none;
}.layout-container-demo .el-main {padding: 0;
}.layout-container-demo .toolbar {display: inline-flex;align-items: center;justify-content: center;height: 100%;right: 20px;
}
/style递归组件MenuTree.vue
templatediv v-foritem in routes :keyitem.path!-- 一级菜单 --el-menu-item :indexitem.path v-if!item.childrenel-iconmessage //el-iconspan v-show!isCollapse{{ item.path }}/span/el-menu-item!-- 多级菜单 --el-sub-menu :indexitem.path v-elsetemplate #title!-- el-icon --el-icon classmore-menu-icon-hovermessage //el-iconspan v-show!isCollapse{{ item.path }}/span/templateMenuTree :routesitem.children/MenuTree/el-sub-menu/div
/templatescript setup langts
import { Message } from element-plus/icons-vuedefineProps({routes: {type: Array,default: () [],},isCollapse: Boolean,
})
/scriptstyle scoped
/* 新增的样式解决箭头问题 */
.more-menu-icon-hover {z-index: 99;background-color: #fff;transition: all 0.3s;
}:deep(.el-sub-menu__title:hover) {.more-menu-icon-hover {background-color: #ecf5ff;}
}
/style但是路由规则数组中我其实做了重定向。也就是路由匹配到 / 的时候会重定向到 /test 也就是Test.vue页面。首页HomeView.vue文件中我指定的有二级路由出口所以Test.vue页面的内容会展示在HomeView.vue页面的路由出口处
templatedivel-button v-permission:[currentRoute]add增加/el-buttonel-button v-permission:[currentRoute]delete删除/el-buttonel-button v-permission:[currentRoute]change修改/el-buttonel-button v-permission:[currentRoute]check查看/el-button/div
/templatescript setup langts
import { ref } from vue
import { useRouter } from vue-routerconst router useRouter()
// 获取当前的路由
const currentRoute ref(router.currentRoute.value.path)
/script
好了到这里前端路由其实就已经做好了。实现的是菜单级别和按钮级别的权限
下面的百度网盘地址有需要的可以自提安装依赖后直接 npm run dev 即可启动
链接https://pan.baidu.com/s/1qYq8TzsroanggPfhVQEPoQ?pwdx89u 提取码x89u